Day 22 - Blocking & Non-blocking Mode

本篇重点

官方说明文件:https://sinotrade.github.io/tutor/advanced/nonblock/

  • Blocking & Non-blocking Mode说明
  • Order event callback
  • Non-blocking place order callback
  • Blocking & Non-blocking Mode执行时间差异

Blocking & Non-blocking Mode 说明

一般我们执行的function都是属於Blocking,也就是要等到function执行结束并return执行结果,程序才会继续往下执行,而Non-blocking Mode就是在call function时,不等function完全执行结束,就直接往下执行。

import shioaji as sj
from shioaji.constant import Action, StockPriceType, FuturesOrderType, FuturesOCType

api = sj.Shioaji(simulation=True)
api.login(
    person_id='PAPIUSER06', 
    passwd='2222'
)

contract = api.Contracts.Futures.MXF['MXF202110']
order = api.Order(action=Action.Buy,
    price=16700,
    quantity=1,
    price_type=StockPriceType.LMT,
    order_type=FuturesOrderType.ROD,
    octype=FuturesOCType.Auto,
    account=api.futopt_account
)

trade = api.place_order(contract, order, timeout=0) #timeout=0,即使用Non-blocking Mode执行
print(trade)

api.logout()

执行结果如下

contract=Future(code='MXFJ1', symbol='MXF202110', name='小型台指10', category='MXF', delivery_month='202110', delivery_date='2021/10/20', underlying_kind='I', unit=1, limit_up=17998.0, limit_down=14726.0, reference=16362.0, update_date='2021/10/07') order=Order(action=<Action.Buy: 'Buy'>, price=16700, quantity=1, account=FutureAccount(person_id='PAPIUSER06', broker_id='F002000', account_id='9102620', signed=True, username='PAPIUSER06'), price_type=<StockPriceType.LMT: 'LMT'>, order_type=<FuturesOrderType.ROD: 'ROD'>) status=OrderStatus(status=<Status.Inactive: 'Inactive'>)

可以看到trade的资讯中并没有委托单号,且OrderStatus为Status.Inactive,因为在Non-blocking Mode下并不会等到place_order完全执行结束後才往下执行,而是不等function回传完整的结果,就直接往下执行下面的程序。在Non-blocking Mode下执行place_order,若要取得委托单完整资讯,可以透过callback方式回传并取得。
在Non-blocking Mode下,callback方式有两种,一种是order callback,可参考Day 15 - Order & Deal Event中的说明,而另一个是Non-blocking place order callback

Non-blocking place order callback

order callback跟Non-blocking place order callback的不同点在於,order callback在宣告完後,呼叫api.set_order_callback将callback程序指定为自行定义的callback function;而Non-blocking place order callback则是在呼叫api.place_order时,传入自行定义的callback function,且此参数只有在Non-blocking Mode才有作用
程序范例说明如下:

import shioaji as sj
from shioaji.constant import Action, StockPriceType, FuturesOrderType, FuturesOCType
from shioaji.order import Trade #汇入Trade物件
import threading #汇入threading模组

api = sj.Shioaji(simulation=True)
api.login(
    person_id='PAPIUSER06', 
    passwd='2222'
)

event = threading.Event() #建立一个Event

def non_blocking_cb(trade:Trade):
    print('__non_blocking_callback__')
    print(trade) #将trade资讯输出
    event.set() #执行set()让主程序继续执行

contract = api.Contracts.Futures.MXF['MXF202110']
order = api.Order(action=Action.Buy,
    price=16700,
    quantity=1,
    price_type=StockPriceType.LMT,
    order_type=FuturesOrderType.ROD,
    octype=FuturesOCType.Auto,
    account=api.futopt_account
)

trade = api.place_order(contract, order, timeout=0, cb=non_blocking_cb) #传入上面定义的callback function
print(trade)
print('wait for callback...')
event.wait() #让主程序进入等待而不直接结束

api.logout()

为了让程序执行後,等待Non-blocking place order callback执行後才结束程序,在这里我们透过Event().wait()来进行等待,并当callback function执行时,呼叫Event().set()让原本的程序继续执行。

Blocking & Non-blocking Mode 执行时间差异

最後,比较一下Blocking & Non-blocking Mode执行时间上的差异,请注意,这个执行时间会受到网路通讯品质及交易时段影响,以下时间仅供参考。
测试的程序内容如下:

import shioaji as sj
from shioaji.constant import Action, StockPriceType, FuturesOrderType, FuturesOCType
from shioaji.order import Trade
import threading, time

api = sj.Shioaji(simulation=True)
api.login(
    person_id='PAPIUSER06', 
    passwd='2222'
)
contract = api.Contracts.Futures.MXF['MXF202110']
order = api.Order(action=Action.Buy,
    price=16750,
    quantity=1,
    price_type=StockPriceType.LMT,
    order_type=FuturesOrderType.ROD,
    octype=FuturesOCType.Auto,
    account=api.futopt_account
)

event = threading.Event()

def non_blocking_cb(trade:Trade):
    print('__non_blocking_callback__')
    # print(trade)
    event.set()

print('start place_order with non-blocking...')
start_time = time.time() #抓取non-blocking开始时间
def non_blocking_cb(trade:Trade):
    print('__non_blocking_callback__')
    # print(trade) #因测试执行时间,所以不做输出动作
    print(f'time of non blocking callback:{time.time()-start_time}') #callback执行时,计算所要花费的时间
    event.set()
trade = api.place_order(contract, order, timeout=0, cb=non_blocking_cb)
# print(trade) #因测试执行时间,所以不做输出动作
print(f'time after place_order:{time.time()-start_time}') #计算api.place_order回传结果所花费的时间
print('wait for non blocking callback...')
event.wait()

print('start place_order with blocking...')
start_time = time.time() #抓取blocking开始时间
def blocking_cb(stat, msg):
    print('__blocking_callback__')
    # print(stat, msg) #因测试执行时间,所以不做输出动作
    print(f'time of blocking callback:{time.time()-start_time}') #callback执行时,计算所要花费的时间
    event.set()

api.set_order_callback(blocking_cb)
trade = api.place_order(contract, order)
# print(trade) #因测试执行时间,所以不做输出动作
print(f'time after place_order:{time.time()-start_time}') #计算api.place_order回传结果所花费的时间
print('wait for blocking callback...')

api.logout()

执行结果如下:

Response Code: 0 | Event Code: 0 | Info: host '218.32.76.102:80', hostname '218.32.76.102:80' IP 218.32.76.102:80 (host 1 of 1) (host connection attempt 1 of 1) (total connection attempt 1 of 1) | Event: Session up
start place_order with non-blocking...
time after place_order:0.015607357025146484
wait for non blocking callback...
__non_blocking_callback__
time of non blocking callback:3.3490772247314453
OrderState.FOrder {'operation': {'op_type': 'New', 'op_code': '00', 'op_msg': ''}, 'order': {'id': 'b0cb8b7d', 'seqno': '980069', 'ordno': 'kY01c', 'account': {'account_type': 'F', 'person_id': '', 'broker_id': 'F002000', 'account_id': '9102620', 'signed': True}, 'action': 'Buy', 'price': 16750.0, 'quantity': 1, 'order_type': 'ROD', 'market_type': 'Night', 'oc_type': 'New', 'subaccount': ''}, 'status': {'id': 'b0cb8b7d', 'exchange_ts': 1633621393, 'modified_price': 0.0, 'cancel_quantity': 0, 'order_quantity': 1}, 'contract': {'security_type': 'FUT', 'code': 'MXF', 'exchange': 'TIM', 'delivery_month': '202110', 'delivery_date': '', 'strike_price': 0.0, 'option_right': 'Future'}}
start place_order with blocking...
OrderState.FOrder {'operation': {'op_type': 'Cancel', 'op_code': '00', 'op_msg': '超过动态价格稳定标准'}, 'order': {'id': 'b0cb8b7d', 'seqno': '980069', 'ordno': 'kY01c', 'account': {'account_type': 'F', 'person_id': '', 'broker_id': 'F002000', 'account_id': '9102620', 'signed': True}, 'action': 'Buy', 'price': 16750.0, 'quantity': 1, 'order_type': 'ROD', 'market_type': 'Day', 'oc_type': 'New', 'subaccount': ''}, 'status': {'id': 'b0cb8b7d', 'exchange_ts': 1633621394, 'modified_price': 0.0, 'cancel_quantity': 1, 'order_quantity': 1}, 'contract': {'security_type': 'FUT', 'code': 'MXF', 'exchange': 'TIM', 'delivery_month': '202110', 'delivery_date': '', 'strike_price': 0.0, 'option_right': 'Future'}}
__blocking_callback__
time of blocking callback:0.0009984970092773438
__blocking_callback__
time of blocking callback:0.0019960403442382812
__blocking_callback__
time of blocking callback:0.0019960403442382812
__blocking_callback__
time of blocking callback:0.0029954910278320312
time after place_order:0.05179405212402344
wait for blocking callback...

从执行结果中,可以看到在non-blocking mode下,place_order会先回传trade资讯,之後才会执行callback;但是在blocking mode下,是先会执行callback,然後place_order才会回传trade资讯。
时间差异比较如下:

time.time()-start_time blocking non-blocking
place_order 0.05179405212402344 0.015607357025146484
callback 0.0029954910278320312 3.3490772247314453

而以下所列出的function,都支援以non-blocking mode的方式执行:

  • ticks
  • place_order
  • update_order
  • cancel_order
  • update_status
  • list_positions

<<:  [Day22] React x TS 中的 Event Handler

>>:  【D23】修改食谱#3:不知道来的客人是谁,先设定预设值

[Day20] Google Map 评论爬虫详细教学

前一篇有提到url的连结不是Google店家页面的连结,需要透过Chrome的开发者工具才能找到~ ...

Day 29 实作 admin_bp (2)

前言 快要结束了,今天要继续写 admin_bp。今天的内容会用到 JS,但我不会多加解释。 pos...

[DAY-11] 诚实敢言最大化 建立回馈循环

只说你敢当面对那个人说的话 越少在背後议论别人 会妨碍效率且引起负面感受的八卦就会减少 诚实就像看...

Day 13:架设 Grafana (1)

那麽今天再回来继续处理我们的 dashboard 吧,上次虽然找到了这个 caddy 的 dashb...

CSS Animation 使 Mobile 网页崩溃!? 效能优化篇(3) - 优化Animation动画~

解决问题搂 终於最後一步要来了!问题已找到~我们动手开始优化吧 1.将连续图拿掉,改用css制作动画...