Skip to content

Commit 1976156

Browse files
committed
xapi python implement
1 parent 4fddd28 commit 1976156

19 files changed

Lines changed: 7191 additions & 0 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,3 +229,4 @@ $RECYCLE.BIN/
229229

230230
# Windows shortcuts
231231
*.lnk
232+
Python/.idea/

Python/base/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# -*- coding: utf-8 -*-
2+
__author__ = 'Chunyou<[email protected]>'

Python/base/abstract_xapi.py

Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
# -*- coding: utf-8 -*-
2+
__author__ = 'Chunyou<[email protected]>'
3+
4+
from .comm import *
5+
6+
7+
class AbstractXApi(object):
8+
is_connected = False
9+
user_login_field = None
10+
_lib_path = None
11+
_callbacks = []
12+
_is_market = True
13+
_xapi = None
14+
debug = False
15+
16+
def __init__(self, xapi_lib_path, lib_path, is_market=True):
17+
"""
18+
create api from the lib_path
19+
:param lib_path:
20+
:return:
21+
"""
22+
self._lib_path = lib_path
23+
self._is_market = is_market
24+
if xapi_lib_path:
25+
self._xapi = CDLL(xapi_lib_path)
26+
27+
def init(self):
28+
"""
29+
load the lib
30+
:return:
31+
"""
32+
pass
33+
34+
def get_last_error(self):
35+
pass
36+
37+
def get_api_type(self):
38+
return Nono
39+
40+
def get_api_version(self):
41+
return "0.1"
42+
43+
def get_api_name(self):
44+
return 'AbstractXApi'
45+
46+
def set_callbacks(self, callbacks):
47+
if not isinstance(callbacks, list):
48+
callbacks = [callbacks]
49+
self._callbacks = callbacks
50+
51+
def connect(self, path, server_info, user_info, count):
52+
"""
53+
Connect to the server.
54+
:param path:
55+
:param server_info:
56+
:param user_info:
57+
:param count:
58+
:return:
59+
"""
60+
pass
61+
62+
def disconnect(self):
63+
pass
64+
65+
def subscribe(self, instrument_ids, exchange_id=b''):
66+
"""
67+
Subscribe market data for the given instruments.
68+
:param instrument_ids: [string], list of instrument ids.
69+
:param exchange_id: string, exchange id
70+
"""
71+
pass
72+
73+
def unsubscribe(self, instrument_ids, exchange_id=b''):
74+
"""
75+
Un-subscribe market data for the given instruments.
76+
:param instrument_ids: [string], list of instrument ids.
77+
:param exchange_id: string, exchange id
78+
"""
79+
pass
80+
81+
def subscribe_quote(self, instrument_ids, exchange_id=b''):
82+
"""
83+
Subscribe market data for the given instruments.
84+
:param instrument_ids: [string], list of instrument ids.
85+
:param exchange_id: string, exchange id
86+
"""
87+
pass
88+
89+
def unsubscribe_quote(self, instrument_ids, exchange_id=b''):
90+
"""
91+
Un-subscribe market data for the given instruments.
92+
:param instrument_ids: [string], list of instrument ids.
93+
:param exchange_id: string, exchange id
94+
"""
95+
pass
96+
97+
def req_qry_instrument(self, instrument_id, exchange_id):
98+
"""
99+
get instrument info
100+
:param instrument_id: string
101+
:param exchange_id: string, exchange id
102+
:return:
103+
"""
104+
pass
105+
106+
def req_qry_investor_position(self, instrument_id, exchange_id):
107+
"""
108+
get investor position
109+
:param instrument_id: string
110+
:param exchange_id: string
111+
:return:
112+
"""
113+
pass
114+
115+
def req_qry_trading_account(self):
116+
"""
117+
get trading account info
118+
:return:
119+
"""
120+
pass
121+
122+
def send_order(self, p_order, p_in_out, count):
123+
"""
124+
create a new order
125+
:param p_order:
126+
:param p_in_out:
127+
:param count:
128+
:return:
129+
"""
130+
pass
131+
132+
def cancel_order(self, p_in, p_out, count):
133+
"""
134+
cancel an order
135+
:param p_in:
136+
:param p_out:
137+
:param count:
138+
:return:
139+
"""
140+
pass
141+
142+
def send_quote(self, p_quote, p_ask_out, p_bid_out, count):
143+
"""
144+
create a new quote
145+
:param p_quote:
146+
:param p_ask_out:
147+
:param p_bid_out:
148+
:param count:
149+
:return:
150+
"""
151+
pass
152+
153+
def cancel_quote(self, p_in, p_out, count):
154+
"""
155+
cancel a quote
156+
:param p_in:
157+
:param p_out:
158+
:param count:
159+
:return:
160+
"""
161+
pass
162+
163+
def _on_response(self, response_type, p_api1, p_api2, double1, double2, ptr1, size1, ptr2, size2, ptr3, size3):
164+
"""
165+
callback from the queue
166+
:param response_type:
167+
:param p_api1:
168+
:param p_api2:
169+
:param double1:
170+
:param double2:
171+
:param ptr1:
172+
:param size1:
173+
:param ptr2:
174+
:param size2:
175+
:param ptr3:
176+
:param size3:
177+
:return:
178+
"""
179+
if self.debug:
180+
print "Response: ", ord(response_type)
181+
if response_type == OnConnectionStatus.value:
182+
self._on_connect_status(p_api2, chr(int(double1)), ptr1, size1)
183+
elif self._callbacks:
184+
for callback in self._callbacks:
185+
if response_type == OnRtnDepthMarketData.value:
186+
obj = cast(ptr1, POINTER(DepthMarketDataField)).contents
187+
if self._is_market:
188+
callback.on_market_rtn_depth_market_data(p_api2, obj)
189+
elif response_type == OnRspQryInstrument.value:
190+
obj = cast(ptr1, POINTER(InstrumentField)).contents
191+
callback.on_trading_rsp_qry_instrument(p_api2, obj, bool(double1))
192+
elif response_type == OnRspQryTradingAccount.value:
193+
obj = cast(ptr1, POINTER(AccountField)).contents
194+
callback.on_trading_rsp_qry_trading_account(p_api2, obj, bool(double1))
195+
elif response_type == OnRspQryInvestorPosition.value:
196+
obj = cast(ptr1, POINTER(PositionField)).contents
197+
callback.on_trading_rsp_qry_investor_position(p_api2, obj, bool(double1))
198+
elif response_type == OnRspQrySettlementInfo.value:
199+
obj = cast(ptr1, POINTER(SettlementInfoField)).contents
200+
callback.on_trading_rsp_qry_settlement_info(p_api2, obj, bool(double1))
201+
elif response_type == OnRtnOrder.value:
202+
obj = cast(ptr1, POINTER(OrderField)).contents
203+
callback.on_trading_rtn_order(p_api2, obj)
204+
elif response_type == OnRtnTrade.value:
205+
obj = cast(ptr1, POINTER(TradeField)).contents
206+
callback.on_trading_rtn_trade(p_api2, obj)
207+
elif response_type == OnRtnQuote.value:
208+
obj = cast(ptr1, POINTER(QuoteField)).contents
209+
callback.on_trading_rtn_quote(p_api2, obj)
210+
elif response_type == OnRtnQuoteRequest.value:
211+
obj = cast(ptr1, POINTER(QuoteRequestField)).contents
212+
callback.on_trading_rtn_quote_request(p_api2, obj)
213+
elif response_type == OnRspQryHistoricalTicks.value:
214+
obj = cast(ptr1, POINTER(TickField)).contents
215+
obj2 = cast(ptr2, POINTER(HistoricalDataRequestField)).contents
216+
callback.on_trading_rsp_qry_historical_ticks(p_api2, obj, obj2, bool(double1))
217+
elif response_type == OnRspQryHistoricalBars.value:
218+
obj = cast(ptr1, POINTER(BarField)).contents
219+
obj2 = cast(ptr2, POINTER(HistoricalDataRequestField)).contents
220+
callback.on_trading_rsp_qry_historical_bars(p_api2, obj, obj2, bool(double1))
221+
elif response_type == OnRspQryInvestor.value:
222+
obj = cast(ptr1, POINTER(InvestorField)).contents
223+
callback.on_trading_rsp_qry_investor(p_api2, obj)
224+
elif response_type == OnFilterSubscribe.value:
225+
instrument = c_char_p(ptr1).value
226+
callback.on_trading_filter_subscribe(p_api2, ExchangeType(double1), size1, size2, size3, instrument)
227+
elif response_type == OnRtnError.value:
228+
obj = cast(ptr1, POINTER(ErrorField)).contents
229+
if self._is_market:
230+
callback.on_market_rsp_error(p_api2, obj, bool(double1))
231+
else:
232+
callback.on_trading_rsp_error(p_api2, obj, bool(double1))
233+
234+
def _on_connect_status(self, p_api, status, p_user_login_field, size):
235+
"""
236+
callback on connect status
237+
:param p_api: int
238+
:param status:
239+
:param p_user_login_field: POINT of RspUserLoginField
240+
:return:
241+
"""
242+
# 连接状态更新
243+
self.is_connected = Done.value == status
244+
245+
obj = RspUserLoginField()
246+
247+
if status in [Logined.value, Disconnected.value, Doing.value] and size > 0:
248+
obj = cast(p_user_login_field, POINTER(RspUserLoginField)).contents
249+
self.user_login_field = obj
250+
251+
if self._callbacks:
252+
for callback in self._callbacks:
253+
if self._is_market:
254+
callback.on_market_connected(p_api, obj, status)
255+
else:
256+
callback.on_trading_connected(p_api, obj, status)
257+
258+
def invoke_log(self, func_name, **kwargs):
259+
for callback in self._callbacks:
260+
if getattr(callback, func_name, None):
261+
getattr(callback, func_name)(kwargs)
262+
263+
def make_response(self, response_type, p_api1=None, p_api2=None, double1=0, double2=0, ptr1=None, size1=0, ptr2=None, size2=0, ptr3=None, size3=0):
264+
"""
265+
Make a response manually, useful in backtesting class
266+
:param response_type:
267+
:param p_api1:
268+
:param p_api2:
269+
:param double1:
270+
:param double2:
271+
:param ptr1:
272+
:param size1:
273+
:param ptr2:
274+
:param size2:
275+
:param ptr3:
276+
:param size3:
277+
:return:
278+
"""
279+
if p_api1:
280+
p_api1 = id(p_api1)
281+
if p_api2:
282+
p_api2 = id(p_api2)
283+
if ptr1:
284+
ptr1 = byref(ptr1)
285+
if size1 == 0:
286+
size1 = 1
287+
if ptr2:
288+
ptr2 = byref(ptr2)
289+
if size2 == 0:
290+
size2 = 1
291+
if ptr3:
292+
ptr3 = byref(ptr3)
293+
if size3 == 0:
294+
size3 = 1
295+
return self._on_response(response_type.value, p_api1, p_api2, double1, double2, ptr1, size1, ptr2, size2, ptr3, size3)

0 commit comments

Comments
 (0)