5
5
import shioaji as sj
6
6
7
7
from .utils import quantity_split , sleep_until
8
+ from .data import Snapshot
8
9
from .simulation_shioaji import SimulationShioaji
9
10
from .stratage import StratageBasic
10
11
from .position import Position , PositionCond , PriceSet
@@ -24,6 +25,7 @@ class SJTrader:
24
25
def __init__ (self , api : sj .Shioaji , simulation : bool = False ):
25
26
self .api = api
26
27
self .positions : Dict [str , Position ] = {}
28
+ self .snapshots : Dict [str , Snapshot ] = {}
27
29
self ._stop_loss_pct = 0.09
28
30
self ._stop_profit_pct = 0.09
29
31
self ._entry_pct = 0.05
@@ -47,6 +49,7 @@ def start(
47
49
intraday_handler_time : datetime .time = datetime .time (8 , 59 , 55 ),
48
50
cover_time : datetime .time = datetime .time (13 , 25 , 59 ),
49
51
):
52
+ self .set_on_tick_handler (self .update_snapshot )
50
53
entry_future = self .executor_on_time (entry_time , self .place_entry_positions )
51
54
self .executor_on_time (
52
55
cancel_preorder_time ,
@@ -137,6 +140,7 @@ def place_entry_order(
137
140
cover_price = [],
138
141
),
139
142
)
143
+ self .snapshots [code ] = Snapshot (price = 0.0 )
140
144
self .api .quote .subscribe (contract , version = QuoteVersion .v1 )
141
145
for price_set in self .positions [code ].cond .entry_price :
142
146
price , price_quantity = price_set .price , price_set .quantity
@@ -168,6 +172,9 @@ def place_entry_positions(self) -> Dict[str, Position]:
168
172
api .update_status ()
169
173
return self .positions
170
174
175
+ def update_snapshot (self , exchange : Exchange , tick : sj .TickSTKv1 ):
176
+ self .snapshots [tick .code ].price = tick .close
177
+
171
178
def cancel_preorder_handler (self , exchange : Exchange , tick : sj .TickSTKv1 ):
172
179
position = self .positions [tick .code ]
173
180
if self .simulation :
@@ -229,6 +236,7 @@ def intraday_handler(self, exchange: Exchange, tick: sj.TickSTKv1):
229
236
self .simulation_api .quote_callback (exchange , tick )
230
237
position = self .positions [tick .code ]
231
238
self .re_entry_order (position , tick )
239
+ self .update_snapshot (exchange , tick )
232
240
# 9:00 -> 13:24:49 stop loss stop profit
233
241
self .stop_loss (position , tick )
234
242
self .stop_profit (position , tick )
@@ -243,7 +251,7 @@ def stop_profit(self, position: Position, tick: sj.TickSTKv1):
243
251
cross = "under"
244
252
for price_set in position .cond .stop_profit_price :
245
253
if op (tick .close , price_set .price ):
246
- self .place_cover_order (position , price_set )
254
+ self .place_cover_order (position , [ price_set ] )
247
255
logger .info (
248
256
f"{ position .contract .code } | price: { tick .close } cross { cross } { price_set .price } "
249
257
f"cover quantity: { price_set .quantity } "
@@ -259,14 +267,14 @@ def stop_loss(self, position: Position, tick: sj.TickSTKv1):
259
267
cross = "over"
260
268
for price_set in position .cond .stop_profit_price :
261
269
if op (tick .close , price_set .price ):
262
- self .place_cover_order (position , price_set )
270
+ self .place_cover_order (position , [ price_set ] )
263
271
logger .info (
264
272
f"{ position .contract .code } | price: { tick .close } cross { cross } { price_set .price } "
265
273
f"cover quantity: { price_set .quantity } "
266
274
)
267
275
268
276
def place_cover_order (
269
- self , position : Position , price_set : Optional [PriceSet ] = None
277
+ self , position : Position , price_sets : List [PriceSet ] = []
270
278
): # TODO with price quantity
271
279
if self .simulation :
272
280
api = self .simulation_api
@@ -275,16 +283,19 @@ def place_cover_order(
275
283
cover_quantity = (
276
284
position .status .open_quantity + position .status .cover_order_quantity
277
285
)
278
- if price_set is None :
279
- price_set = self .stratage .cover_price_set (position )[0 ]
280
- skip = (cover_quantity == 0 )
281
- if cover_quantity < 0 :
286
+ if not price_sets :
287
+ price_sets = self .stratage .cover_price_set (
288
+ position , self .snapshots [position .contract .code ]
289
+ )
290
+ if cover_quantity == 0 :
291
+ return
292
+ elif cover_quantity < 0 :
282
293
action = Action .Buy
283
294
op = max
284
- elif cover_quantity > 0 :
295
+ else :
285
296
action = Action .Sell
286
297
op = min
287
- if not skip :
298
+ for price_set in price_sets :
288
299
cover_quantity_set = op (cover_quantity , price_set .quantity )
289
300
if cover_quantity_set :
290
301
quantity_s = quantity_split (cover_quantity_set , threshold = 499 )
@@ -305,7 +316,7 @@ def place_cover_order(
305
316
position .cover_trades .append (trade )
306
317
api .update_status (trade = trade )
307
318
308
- def open_position_cover (self ):
319
+ def open_position_cover (self , onclose : bool = True ):
309
320
if self .simulation :
310
321
api = self .simulation_api
311
322
else :
@@ -334,7 +345,12 @@ def open_position_cover(self):
334
345
]:
335
346
api .cancel_order (trade , timeout = 0 )
336
347
# event wait cancel
337
- self .positions = self .stratage .cover_positions (self .positions )
348
+ if onclose :
349
+ self .positions = self .stratage .cover_positions_onclose (self .positions )
350
+ else :
351
+ self .positions = self .stratage .cover_positions (
352
+ self .positions , self .snapshots
353
+ )
338
354
for code , position in self .positions .items ():
339
355
if position .status .open_quantity :
340
356
self .place_cover_order (position , position .cond .cover_price )
0 commit comments