hhtrade 0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
hhtrade-0.1/PKG-INFO ADDED
@@ -0,0 +1,3 @@
1
+ Metadata-Version: 2.1
2
+ Name: hhtrade
3
+ Version: 0.1
hhtrade-0.1/README.md ADDED
@@ -0,0 +1 @@
1
+ for fun
File without changes
@@ -0,0 +1,265 @@
1
+ import time
2
+ import pandas as pd
3
+ from tqsdk import TqApi, TqAuth, TqKq, TargetPosTask
4
+ from tqsdk.datetime import _cst_now,_get_trade_timestamp,_datetime_to_timestamp_nano,_convert_user_input_to_nano
5
+ from datetime import datetime,timedelta
6
+ import math
7
+ import numpy as np
8
+ from itertools import groupby
9
+ import random
10
+ import os
11
+ import csv
12
+
13
+
14
+ class orderclass:
15
+ def __init__(self,api = None , targetposition = None ):
16
+ self.api = api
17
+ self.targetposition = targetposition
18
+ assert self.checkcorrectcode(), "请检查品种代码"
19
+ self.oldposition = self.get_initposition()
20
+ self.printposition()
21
+ self.get_orderquote()
22
+
23
+
24
+ def checkcorrectcode(self):
25
+ for k in self.targetposition.keys():
26
+ try:
27
+ quote = self.api.get_quote(k)
28
+ except:
29
+ print(f"{k} 查询合约服务报错 ,请检查品种代码")
30
+ return False
31
+ return True
32
+
33
+
34
+
35
+
36
+
37
+ def printposition(self):
38
+ initialholdings = self.api.get_position()
39
+ for k in initialholdings.keys():
40
+ p = self.api.get_position(f"{k}")
41
+ print(
42
+ f"{p.instrument_id} 历史多头持仓 {p.pos_long_his}, 今日多头持仓 {p.pos_long_today}, 历史空头持仓 {p.pos_short_his} , 今日空头持仓 {p.pos_short_today}, 当前多头总持仓 {p.pos_long}, 当前空头总持仓 {p.pos_short}")
43
+
44
+ def get_initposition(self):
45
+ initialholdings = self.api.get_position()
46
+ initialholdingdict = {}
47
+ for k in initialholdings.keys():
48
+ initialholdingdict[k] = initialholdings[k].volume_long - initialholdings[k].volume_short
49
+ return initialholdingdict
50
+
51
+
52
+ def get_orderquote(self):
53
+ order_diff, order_direction = self.calculate_order(self.oldposition, self.targetposition )
54
+ self.orderqueue = self.order_to_queue(dict_data=order_diff.copy())
55
+ self.orderplan = self.orderplanset( oldposition = self.oldposition,targetposition = self.targetposition,\
56
+ orderqueue = self.orderqueue,\
57
+ order_direction = order_direction, \
58
+ maxvol=5)
59
+
60
+
61
+ def calculate_order(self,dict1, dict2):
62
+ """
63
+ 计算交割单的差异和方向
64
+ """
65
+ all_keys = set(dict1.keys()).union(set(dict2.keys()))
66
+ difference = {}
67
+ direction = {}
68
+ for key in all_keys:
69
+ difference[key] = abs(dict2.get(key, 0) - dict1.get(key, 0))
70
+ direction[key] = int(np.sign(dict2.get(key, 0) - dict1.get(key, 0)))
71
+ return difference, direction
72
+
73
+ def order_to_queue(self, dict_data):
74
+ """
75
+ 将订单dict 变为执行序列 完全随机
76
+ """
77
+ # 获取股指期货序列
78
+ queue = []
79
+ for key, value in dict_data.items():
80
+ queue.extend([key] * value)
81
+ # 打乱股指期货序列
82
+ random.shuffle(queue)
83
+ # 到这里,理论上应该 dict_data 全是 0
84
+ return queue
85
+
86
+ def dictmatch(self,dict1, dict2):
87
+ newdict = dict1.copy()
88
+ for k in dict2:
89
+ if k not in dict1:
90
+ newdict[k] = 0
91
+ return newdict
92
+
93
+ def orderplanset(self, oldposition, targetposition, orderqueue, order_direction, maxvol=5):
94
+ """
95
+ 这一步的目的是,限定了单次调仓的最大笔数。因为可能出现国债太多,尽管已经均匀切分,但是对市场冲击还是很大,通过maxvol,设定最大下单手数
96
+ """
97
+ grouped_order = [(key, len(list(group))) for key, group in groupby(orderqueue)]
98
+ result_order = []
99
+ for key, count in grouped_order:
100
+ while count > maxvol:
101
+ result_order.append((key, maxvol))
102
+ count -= maxvol
103
+ if count > 0:
104
+ result_order.append((key, count))
105
+ orderplan = []
106
+
107
+ recorddict = self.dictmatch(oldposition, targetposition)
108
+ targetpositiondict = self.dictmatch(targetposition, oldposition)
109
+
110
+ for order_tp in result_order:
111
+ recorddict[order_tp[0]] = recorddict[order_tp[0]] + order_direction[order_tp[0]] * order_tp[1]
112
+ orderplan.append([order_tp[0], recorddict[order_tp[0]]])
113
+
114
+ orderplan = pd.DataFrame(orderplan, columns=['sid', 'targetvol'])
115
+
116
+ last_tg = pd.DataFrame(oldposition.items(), columns=['sid', 'targetvol'])._append(orderplan).drop_duplicates(
117
+ subset='sid', keep='last')
118
+
119
+ # 检查经过目标调仓序列是不是可以完成调仓目标
120
+ if targetpositiondict == last_tg.set_index('sid').to_dict()['targetvol']:
121
+ print("目标调仓序列可以达到最终持仓目标")
122
+ else:
123
+ assert False, "目标调仓序列不可以达到最终持仓目标"
124
+ return orderplan
125
+
126
+ def dynamic_sendorder(self, dforderplan = None, timestart = None, timeend =None ):
127
+ """
128
+ datetime.strptime(timestart, '%Y-%m-%d %H:%M:%S.%f')
129
+ """
130
+ print("开始执行交易")
131
+ if len(dforderplan) == 0:
132
+ print("无需调仓")
133
+ return 0
134
+ timestart = datetime.strptime(timestart, '%Y%m%d %H:%M:%S')
135
+ timeend = datetime.strptime(timeend, '%Y%m%d %H:%M:%S')
136
+ timestart_nano, timeend_nano = _convert_user_input_to_nano(timestart,timeend )
137
+
138
+ #每次成交中间间隔纳秒
139
+ timedaly = int((timestart_nano - timeend_nano) / (len(dforderplan)) / 1000000000)
140
+
141
+ unfinishorder = []
142
+
143
+ for index, orderrow in self.orderplan.iterrows():
144
+ # break
145
+ # print(orderrow)
146
+ newsetposition = self.get_initposition()
147
+
148
+ if orderrow.sid in newsetposition:
149
+ # print(index, orderrow)
150
+ # "ACTIVE" 对价下单,在持仓调整过程中,若下单方向为买,对价为卖一价;若下单方向为卖,对价为买一价。
151
+ # "昨开" 表示先平昨仓,再开仓,禁止平今仓,适合股指这样平今手续费较高的品种
152
+ target_pos_active = TargetPosTask(self.api, orderrow.sid, price="ACTIVE",offset_priority="昨开")
153
+ target_pos_active.set_target_volume(orderrow.targetvol)
154
+ nethold = target_pos_active._pos.volume_long - target_pos_active._pos.volume_short
155
+ t = time.time()
156
+ ifhavetime = True
157
+ while (nethold)!= orderrow.targetvol and ifhavetime:
158
+ self.api.wait_update()
159
+ nethold = target_pos_active._pos.volume_long - target_pos_active._pos.volume_short
160
+ print(f"当前{orderrow.sid} 目标变动 {orderrow.targetvol} 当前持仓 空 {target_pos_active._pos.volume_short} 多 {target_pos_active._pos.volume_long}" )
161
+ costtime = time.time() - t
162
+ if costtime>timedaly:
163
+ ifhavetime = False
164
+ unfinishorder.append([orderrow.sid, orderrow.targetvol , nethold ] )
165
+
166
+ else:
167
+ directioni = "BUY" if orderrow.targetvol >0 else "SELL"
168
+ quote = self.api.get_quote(orderrow.sid)
169
+ if directioni == "BUY":
170
+ lc = quote.ask_price1
171
+ else:
172
+ lc = quote.bid_price1
173
+ order = api.insert_order(symbol = orderrow.sid, direction=directioni, offset="OPEN",
174
+ limit_price=lc,
175
+ volume = orderrow.targetvol)
176
+ ifhavetime = True
177
+ t = time.time()
178
+ while order.status != "FINISHED":
179
+ self.api.wait_update()
180
+ print("单状态: %s, 已成交: %d 手" % (order.status, order.volume_orign - order.volume_left))
181
+ costtime = time.time() - t
182
+ if costtime>timedaly:
183
+ ifhavetime = False
184
+ unfinishorder.append([orderrow.sid, orderrow.targetvol, order.volume_orign - order.volume_left])
185
+
186
+ timestart_nano_s, timeend_nano_e = _convert_user_input_to_nano( _cst_now(), timeend )
187
+ timedaly = int(( timeend_nano_e - timestart_nano_s)/ (len(dforderplan)-index) /1000000000 )
188
+ time.sleep(timedaly )
189
+
190
+ print("调仓完成")
191
+ return unfinishorder
192
+
193
+ def tradeorder(self, timestart = None, timeend = None , delaydt = 60):
194
+
195
+ timestart = self.checktimestart(inputtime=timestart)
196
+ timeend = self.checktimeend(inputtime=timeend, delaydt=delaydt)
197
+ unfinishorder = self.dynamic_sendorder( dforderplan= self.orderplan , timestart=timestart, timeend=timeend)
198
+ if unfinishorder == 0:
199
+ self.printposition()
200
+ else:
201
+ assert len(unfinishorder) == 0, "重大错误,存在未成功下单订单"
202
+
203
+
204
+
205
+ def checktimeend(self, inputtime = None, delaydt = 60):
206
+ """
207
+ 检查输入时间是不是晚于当前时间
208
+ inputtime 格式需要满足 '%Y%m%d %H:%M:%S' 例如 '20240815 10:10:00'
209
+ """
210
+ if inputtime is None:
211
+ inputtime = datetime.now() + timedelta(seconds=delaydt)
212
+ return inputtime.strftime( '%Y%m%d %H:%M:%S')
213
+ deltat = (datetime.now() - datetime.strptime(inputtime, '%Y%m%d %H:%M:%S')).total_seconds()
214
+ assert (deltat < 0 ),'输入时间 应该晚于当前时间'
215
+
216
+
217
+
218
+ def checktimestart(self, inputtime = None):
219
+ """
220
+ 检查输入时间是不是晚于当前时间
221
+ inputtime 格式需要满足 '%Y%m%d %H:%M:%S' 例如 '20240815 10:10:00'
222
+ """
223
+ if inputtime is None:
224
+ inputtime = time.strftime('%Y%m%d %H:%M:%S', time.localtime())
225
+ return inputtime
226
+ else:
227
+ deltat = (datetime.now() - datetime.strptime(inputtime, '%Y%m%d %H:%M:%S')).total_seconds()
228
+ if deltat >0 :
229
+ inputtime = time.strftime('%Y%m%d %H:%M:%S', time.localtime())
230
+ print("调整输入时间为当前时间")
231
+ return inputtime
232
+ else:
233
+ while deltat<0:
234
+ deltat = (datetime.now()- datetime.strptime(inputtime, '%Y%m%d %H:%M:%S')).seconds
235
+ print(f"未到下单时间 需要等待 {deltat}")
236
+ time.sleep(1)
237
+ inputtime = time.strftime('%Y%m%d %H:%M:%S', time.localtime())
238
+ return inputtime
239
+
240
+ def downloader_orders(self):
241
+ order_cols = ["order_id", "exchange_order_id", "exchange_id", "instrument_id", "direction", "offset", "status",
242
+ "volume_orign", "volume_left", "limit_price", "price_type", "volume_condition", "time_condition",
243
+ "insert_date_time", "last_msg"]
244
+ trade_cols = ["trade_id", "order_id", "exchange_trade_id", "exchange_id", "instrument_id", "direction",
245
+ "offset", "price", "volume", "trade_date_time"]
246
+ def write_csv(file_name, cols, datas):
247
+ file_exists = os.path.exists(file_name) and os.path.getsize(file_name) > 0
248
+ with open(file_name, 'a', newline='') as csvfile:
249
+ csv_writer = csv.writer(csvfile, dialect='excel')
250
+ if not file_exists:
251
+ csv_writer.writerow(['datetime'] + cols)
252
+ for item in datas.values():
253
+ if 'insert_date_time' in cols:
254
+ dt = datetime.fromtimestamp(item['insert_date_time'] / 1e9).strftime('%Y-%m-%d %H:%M:%S.%f')
255
+ elif 'trade_date_time' in cols:
256
+ dt = datetime.fromtimestamp(item['trade_date_time'] / 1e9).strftime('%Y-%m-%d %H:%M:%S.%f')
257
+ else:
258
+ dt = None
259
+ row = [dt] + [item[k] for k in cols]
260
+ csv_writer.writerow(row)
261
+ with self.api as api:
262
+ # 将当前账户下全部委托单、成交信息写入 csv 文件中
263
+ write_csv("orders.csv", order_cols, api.get_order())
264
+ write_csv("trades.csv", trade_cols, api.get_trade())
265
+
@@ -0,0 +1,3 @@
1
+ Metadata-Version: 2.1
2
+ Name: hhtrade
3
+ Version: 0.1
@@ -0,0 +1,9 @@
1
+ README.md
2
+ setup.py
3
+ hhtrade/__init__.py
4
+ hhtrade/hhtrade.py
5
+ hhtrade.egg-info/PKG-INFO
6
+ hhtrade.egg-info/SOURCES.txt
7
+ hhtrade.egg-info/dependency_links.txt
8
+ hhtrade.egg-info/not-zip-safe
9
+ hhtrade.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+
@@ -0,0 +1 @@
1
+ hhtrade
hhtrade-0.1/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
hhtrade-0.1/setup.py ADDED
@@ -0,0 +1,5 @@
1
+ from setuptools import setup
2
+
3
+ setup(name='hhtrade',
4
+ version='0.1',
5
+ zip_safe=False)