hikyuu2/hikyuu/puppet.py

298 lines
12 KiB
C++
Raw Normal View History

2017-06-29 14:19:02 +08:00
"""
线(Puppet UIAutomation API)线(Puppet Quant Framework)
624585416
2017-06-29 14:19:02 +08:00
"""
__author__ = "睿瞳深邃(https://github.com/Raytone-D)"
2017-06-29 14:19:02 +08:00
__project__ = 'Puppet'
__version__ = "0.4.12"
__license__ = 'MIT'
2017-06-29 14:19:02 +08:00
# coding: utf-8
import ctypes
from functools import reduce
import time
import pyperclip
MSG = {'WM_SETTEXT': 12,
'WM_GETTEXT': 13,
'WM_KEYDOWN': 256,
'WM_KEYUP': 257,
'WM_COMMAND': 273,
'BM_CLICK': 245,
'CB_GETCOUNT': 326,
'CB_SETCURSEL': 334,
'CBN_SELCHANGE': 1,
'COPY_DATA': 57634}
NODE = {'FRAME': (59648, 59649),
'FORM': (59648, 59649, 1047, 200, 1047),
'ACCOUNT': (59392, 0, 1711),
'COMBO': (59392, 0, 2322),
'BUY': (161, (1032, 1033, 1034), 1006),
'SELL':(162, (1032, 1033, 1034), 1006),
2017-06-29 14:19:02 +08:00
'': 163,
'': 512,
'': 554,
'': 1070}
TWO_WAY = {'': 1032,
'': 1033,
'': 1034,
'': 1006,
'': 1035,
'': 1058,
'': 1039,
'': 1008,
'': 1038,
'': 32790,
'': 30001,
'': 30002,
'': 30003,
'': 1047}
TAB = {'': ord('W'),
'': ord('E'),
'': ord('R')}
SCHEDULE = {'': '',
'': '',
'': '',
'': ''}
CANCEL = {'': 1098,
'': 1099,
'': 30001,
'': 30002,
'': 30003,
'': 3348,
'': 3349}
NEW = {'': 1032,
'': 1036,
'': 1033,
'': 1018,
'': 1034,
'': 1006}
RAFFLE = ['', '', '', '']
#CMD = {'COPY': 57634}
2017-06-29 14:19:02 +08:00
VKCODE = {'F1': 112,
'F2': 113,
'F3': 114,
'F4': 115,
'F5': 116,
'F6': 117}
MKT = {'CYB': '3',
'SH': '7',
'SZ': '0',
'': '3',
'': '7',
'': '0'}
op = ctypes.windll.user32
def switch_combo(index, idCombo, hCombo):
op.SendMessageW(hCombo, MSG['CB_SETCURSEL'], index, 0)
op.SendMessageW(op.GetParent(hCombo), MSG['WM_COMMAND'], MSG['CBN_SELCHANGE']<<16|idCombo, hCombo)
class Puppet:
2017-06-29 14:19:02 +08:00
"""
2017-06-29 14:19:02 +08:00
# 方法 # '委买': buy(), '委卖': sell(), '撤单': cancel(), '打新': raffle(),
# 属性 # '帐号': account, '可用余额': balance, '持仓': position, '成交': deals, '可撤委托': cancelable,
# # '新股': new, '中签': bingo,
"""
def __init__(self, main=None, title='5.0'):
2017-06-29 14:19:02 +08:00
print('...')
self.main = main or op.FindWindowW(0, title)
self.switch = lambda node: op.SendMessageW(self.main, MSG['WM_COMMAND'], node, 0)
self._order = []
for i in (NODE['BUY'],NODE['SELL']):
node, parts, button = i
self.switch(node)
time.sleep(0.3)
x = reduce(op.GetDlgItem, NODE['FRAME'], self.main)
self._order.append((tuple(op.GetDlgItem(x, v) for v in parts), button, x))
2017-06-29 14:19:02 +08:00
op.SendMessageW(self.main, MSG['WM_COMMAND'], NODE[''], 0) #
self.wait_a_second = lambda sec=0.2: time.sleep(sec)
self.wait_a_second() # (0.01~0.5)
self.buff = ctypes.create_unicode_buffer(32)
self.two_way = reduce(op.GetDlgItem, NODE['FRAME'], self.main)
2017-06-29 14:19:02 +08:00
self.members = {k: op.GetDlgItem(self.two_way, v) for k, v in TWO_WAY.items()}
print('') if self.main else print("没找到已登录的客户交易端,我先撤了!")
# 获取登录账号
self.account = reduce(op.GetDlgItem, NODE['ACCOUNT'], self.main)
2017-06-29 14:19:02 +08:00
op.SendMessageW(self.account, MSG['WM_GETTEXT'], 32, self.buff)
self.account = self.buff.value
self.combo = reduce(op.GetDlgItem, NODE['COMBO'], self.main)
2017-06-29 14:19:02 +08:00
self.count = op.SendMessageW(self.combo, MSG['CB_GETCOUNT'])
def switch_tab(self, hCtrl, keyCode, param=0): #
op.PostMessageW(hCtrl, MSG['WM_KEYDOWN'], keyCode, param)
self.wait_a_second(0.5)
op.PostMessageW(hCtrl, MSG['WM_KEYUP'], keyCode, param)
def copy_data(self, key=0): # background mode
"将CVirtualGridCtrl|Custom<n>的数据复制到剪贴板,默认取当前的表格"
if key:
self.switch_tab(self.two_way, key) # ('W')('E')('R')
print("正在等待实时数据返回,请稍候...")
pyperclip.copy('')
# 查到只有列表头的空白数据等3秒...orz
for i in range(10):
time.sleep(0.3)
op.SendMessageW(reduce(op.GetDlgItem, NODE['FORM'], self.main),
MSG['WM_COMMAND'], MSG['COPY_DATA'], NODE['FORM'][-1])
if len(pyperclip.paste().splitlines()) > 1:
break
2017-06-29 14:19:02 +08:00
return pyperclip.paste()
def buy(self, symbol, price, qty):
self.switch(NODE['BUY'][0])
tuple(map(lambda hCtrl, arg: op.SendMessageW(
hCtrl, MSG['WM_SETTEXT'], 0, str(arg)), self._order[0][0], (symbol, price, qty)))
op.PostMessageW(self._order[0][-1], MSG['WM_COMMAND'], self._order[0][1], 0)
def sell(self, symbol, price, qty):
self.switch(NODE['SELL'][0])
tuple(map(lambda hCtrl, arg: op.SendMessageW(
hCtrl, MSG['WM_SETTEXT'], 0, str(arg)), self._order[1][0], (symbol, price, qty)))
op.PostMessageW(self._order[1][-1], MSG['WM_COMMAND'], self._order[1][1], 0)
def buy2(self, symbol, price, qty): # (B)
self.switch(NODE[''])
2017-06-29 14:19:02 +08:00
op.SendMessageW(self.members[''], MSG['WM_SETTEXT'], 0, str(symbol))
op.SendMessageW(self.members[''], MSG['WM_SETTEXT'], 0, str(price))
op.SendMessageW(self.members[''], MSG['WM_SETTEXT'], 0, str(qty))
#op.SendMessageW(self.members['买入'], MSG['BM_CLICK'], 0, 0)
op.PostMessageW(self.two_way, MSG['WM_COMMAND'], TWO_WAY[''], self.members[''])
def sell2(self, symbol, price, qty): # (S)
self.switch(NODE[''])
2017-06-29 14:19:02 +08:00
op.SendMessageW(self.members[''], MSG['WM_SETTEXT'], 0, str(symbol))
op.SendMessageW(self.members[''], MSG['WM_SETTEXT'], 0, str(price))
op.SendMessageW(self.members[''], MSG['WM_SETTEXT'], 0, str(qty))
#op.SendMessageW(self.members['卖出'], MSG['BM_CLICK'], 0, 0)
op.PostMessageW(self.two_way, MSG['WM_COMMAND'], TWO_WAY[''], self.members[''])
2017-06-29 14:19:02 +08:00
def refresh(self): # (F5)
op.PostMessageW(self.two_way, MSG['WM_COMMAND'], TWO_WAY[''], self.members[''])
def cancel(self, symbol=None, way=''):
op.SendMessageW(self.main, MSG['WM_COMMAND'], NODE[''], 0) #
if way and str(symbol).isdecimal():
#print(self.copy_data())
self.cancel_c = reduce(op.GetDlgItem, NODE['FRAME'], self.main)
2017-06-29 14:19:02 +08:00
self.cancel_ctrl = {k: op.GetDlgItem(self.cancel_c, v) for k, v in CANCEL.items()}
op.SendMessageW(self.cancel_ctrl[''], MSG['WM_SETTEXT'], 0, symbol)
self.wait_a_second()
op.PostMessageW(self.cancel_c, MSG['WM_COMMAND'], CANCEL[''], self.cancel_ctrl[''])
op.PostMessageW(self.cancel_c, MSG['WM_COMMAND'], CANCEL[way], self.cancel_ctrl[way])
schedule = self.copy_data()
op.SendMessageW(self.main, MSG['WM_COMMAND'], NODE[''], 0) #
return schedule
@property
def balance(self):
print(': %s' % ('$'*68))
op.SendMessageW(self.members[''], MSG['WM_GETTEXT'], 32, self.buff)
return self.buff.value
@property
def position(self):
print(': %s' % ('$'*68))
return self.copy_data(TAB[''])
@property
def market_value(self):
form = (x.split() for x in self.position.splitlines())
index = next(form).index('')
return sum((float(row[index]) for row in form))
@property
def deals(self):
print(': %s' % ('$'*68))
return self.copy_data(TAB[''])
@property
def cancelable(self):
print(': %s' % ('$'*68))
return self.cancel(way=False)
@property
def new(self):
print(': %s' % ('$'*68))
return self.raffle(way=False)
@property
def bingo(self):
print(': {0}'.format('$'*68))
op.SendMessageW(self.main, MSG['WM_COMMAND'], NODE[''], 0)
return self.copy_data()
def cancel_all(self): # (Z)
op.PostMessageW(self.two_way, MSG['WM_COMMAND'], 30001, self.members[30001])
def cancel_buy(self): # (X)
op.PostMessageW(self.two_way, MSG['WM_COMMAND'], 30002, self.members[30002])
def cancel_sell(self): # (C)
op.PostMessageW(self.two_way, MSG['WM_COMMAND'], 30003, self.members[30003])
def cancel_last(self): #
op.PostMessageW(self.two_way, MSG['WM_COMMAND'], 2053, self.members[2053])
def cancel_same(self): #
#op.PostMessageW(self.two_way, WM_COMMAND, 30022, self.members[30022])
pass
def raffle(self, skip=None, way=True): #
op.SendMessageW(self.main, MSG['WM_COMMAND'], NODE[''], 0)
#close_pop() # 弹窗无需关闭,不影响交易。
schedule = self.copy_data()
if way:
print("开始打新股%s" % ('>'*68))
print(schedule)
self.raffle_c = reduce(op.GetDlgItem, NODE['FRAME'], self.main)
2017-06-29 14:19:02 +08:00
self.raffle_ctrl = {k: op.GetDlgItem(self.raffle_c, v) for k, v in NEW.items()}
new = [x.split() for x in schedule.splitlines()]
index = [new[0].index(x) for x in RAFFLE if x in new[0]] # 0, 1, 2
new = map(lambda x: [x[y] for y in index], new[1:])
for symbol, price, qty in new:
if symbol[0] == skip:
print({symbol: (qty, "跳过<%s>开头的新股!" % skip)})
continue
if qty == '0':
print({symbol: (qty, "数量为零")})
continue
op.SendMessageW(self.raffle_ctrl[''], MSG['WM_SETTEXT'], 0, symbol)
self.wait_a_second(1)
#op.SendMessageW(self.raffle_ctrl['可申购数量'], MSG['WM_GETTEXT'], 32, self.buff)
#qty = self.buff.value
op.SendMessageW(self.raffle_ctrl[''], MSG['WM_SETTEXT'], 0, qty)
self.wait_a_second()
op.PostMessageW(self.raffle_c, MSG['WM_COMMAND'], NEW[''], self.raffle_ctrl[''])
print({symbol: (qty, "已申购")})
print(self.cancelable)
op.SendMessageW(self.main, MSG['WM_COMMAND'], NODE[''], 0) #
return schedule
if __name__ == '__main__':
trader = Puppet()
#trader = Puppet(title='广发证券核新网上交易系统7.60')
2017-06-29 14:19:02 +08:00
if trader.account:
print(trader.account) #
#print(trader.new) # 查当天新股名单
#trader.raffle(MKT['创业板']) # 确定打新股,跳过创业板不打。
#print(trader.balance) # 可用余额
#print(trader.position) # 实时持仓
#print(trader.deals) # 当天成交
#print(trader.cancelable) # 可撤委托
print(trader.market_value)