基于TFast的量化交易框架(模拟账户+模拟柜台)

更多精彩内容详见个人量化交易专辑索引

1. 启动前回调,添加交易账户,订阅行情,策略初始化计算等

def pre_start(context):
    context.log.info("pre_start")
    # 确定日期
    today = datetime.datetime.now().strftime('%Y-%m-%d')
    context.log.warning("today: {}".format(today))
    private['today'] = today
    
    # 绑定账户
    context.add_account(SOURCE, ACCOUNT, 2000000.0)

    # 无法在订阅阶段获取账户持仓情况,因此先要更新当天的subscribe.txt
    try:
    	# 按subscribe.txt订阅股票
        subscribe_dict = json.load(open(SUBSCRIBE_FILE,'r'))
        if subscribe_dict['date'] == today:
            for exchange_id in subscribe_dict['exchange']:
                if len(subscribe_dict['exchange'][exchange_id]) > 0:
                    context.subscribe(SOURCE, subscribe_dict['exchange'][exchange_id], exchange_id)
    except:
        context.log.warning("loss subscribe")

2. 启动准备工作完成后回调,策略只能在本函数回调以后才能进行获取持仓和报单

def post_start(context):
    context.log.info("post_start")
    today = private['today']
        
    # 读取账户资金、持仓
    book = context.get_account_book(SOURCE, ACCOUNT)
    asset = book.asset
    context.log.warning("crash: {}".format(asset.avail))
    positions = book.long_positions
    for key in positions:
        pos = positions[key]
        context.log.warning("(instrument_id){} (direction){} (volume){} (yesterday_volume){}".format(
                pos.instrument_id, pos.direction, pos.volume, pos.yesterday_volume))

    # 生成账本
    try:
        os.remove(BOOK_FILE)
    except:
        if os.path.exists(BOOK_FILE):
            context.log.error("{} remove failed".format(BOOK_FILE))
            return 
    private['book'] = {}
    private['book']['crash'] = asset.avail
    private['book']['hold_dict'] = {}
    for key in positions:
        pos = positions[key]
        if pos.volume == 0:
            continue
        private['book']['hold_dict'][pos.instrument_id] = {
                'buy_date':datetime.datetime.strptime(pos.trading_day, '%Y%m%d').strftime('%Y-%m-%d'),
                'orig_share':pos.volume,
                'cost':pos.position_cost_price*pos.volume,
                }
    json.dump(private['book'], open(BOOK_FILE, 'w'))

    # 量化选股,确定买入、卖出股票具体份额
    try:
        os.remove(TRADE_FILE)
    except:
        if os.path.exists(TRADE_FILE):
            context.log.error("{} remove failed".format(TRADE_FILE))
            return
    child = subprocess.Popen(['trade-assistant.bat'], stdout=subprocess.PIPE)
    child.wait()
    try:
        trade = json.load(open(TRADE_FILE,'r'))
    except:
        context.log.warning("loss trade")
        return
    for code in trade['sale_codes']:
        trade['sale_codes'][code]['on_ask'] = 0
    for code in trade['buy_codes']:
        trade['buy_codes'][code]['on_bid'] = 0
    private['trade'] = trade

    # 生成订阅标的subscribe.txt
    try:
        os.remove(SUBSCRIBE_FILE)
    except:
        if os.path.exists(SUBSCRIBE_FILE):
            context.log.error("{} remove failed".format(SUBSCRIBE_FILE))
            return  
    subscribe_dict = {}
    subscribe_dict['date'] = today
    subscribe_dict['exchange'] = {}
    subscribe_dict['exchange'][Exchange.SSE] = []
    subscribe_dict['exchange'][Exchange.SZE] = []
    for code in trade['sale_codes']:
        market = trade['sale_codes'][code]['market']
        if market == 'SH':
            subscribe_dict['exchange'][Exchange.SSE].append(code)
        elif market == 'SZ':
            subscribe_dict['exchange'][Exchange.SZE].append(code)
    for code in trade['buy_codes']:
        market = trade['buy_codes'][code]['market']
        if market == 'SH':
            subscribe_dict['exchange'][Exchange.SSE].append(code)
        elif market == 'SZ':
            subscribe_dict['exchange'][Exchange.SZE].append(code)
    json.dump(subscribe_dict, open(SUBSCRIBE_FILE, 'w'))

3. 收到快照行情时回调,行情信息通过 quote 对象获取

def on_quote(context, quote):
    #context.log.info("[on_quote] {}".format(quote))
    code = quote.instrument_id
    sale_codes = private['trade']['sale_codes']
    buy_codes = private['trade']['buy_codes']

    # 尝试分批买入、卖出,直到份额用完
    if code in sale_codes:
        ask_share = sale_codes[code]['ask_share']
        if ask_share > 0:
            order_id = context.insert_order(code, Exchange.SSE, ACCOUNT, quote.last_price, ask_share, PriceType.Limit, Side.Sell, Offset.Open)
            if order_id > 0:
                sale_codes[code]['on_ask'] += ask_share
                sale_codes[code]['ask_share'] = 0
                context.log.info("[order] (order_id){} (code){} (ask_share){}".format(order_id, code, ask_share))
                # 通过添加时间回调,在三秒以后撤单
                context.add_timer(context.now() + 3 * 1000000000, lambda ctx, event: cancel_order(ctx, order_id))
    if code in buy_codes:
        bid_share = buy_codes[code]['bid_share']
        if bid_share > 0:
            order_id = context.insert_order(code, Exchange.SSE, ACCOUNT, quote.last_price, bid_share, PriceType.Limit, Side.Buy, Offset.Open)
            if order_id > 0:
                buy_codes[code]['on_bid'] += bid_share
                buy_codes[code]['bid_share'] = 0
                context.log.info("[order] (order_id){} (code){} (bid_share){}".format(order_id, code, bid_share))
                # 通过添加时间回调,在三秒以后撤单
                context.add_timer(context.now() + 3 * 1000000000, lambda ctx, event: cancel_order(ctx, order_id))

4. 收到订单状态回报时回调

def on_order(context, order):
    #context.log.info("[on_order] {}".format(order))
    code = order.instrument_id
    sale_codes = private['trade']['sale_codes']
    buy_codes = private['trade']['buy_codes']
    
    if (order.status == OrderStatus.Cancelled) or \
            (order.status == OrderStatus.Error) or \
            (order.status == OrderStatus.PartialFilledNotActive):
        if code in sale_codes:
            sale_codes[code]['ask_share'] += order.volume_left
            sale_codes[code]['on_ask'] -= order.volume_left
        elif code in buy_codes:
            buy_codes[code]['bid_share'] += order.volume_left
            buy_codes[code]['on_bid'] -= order.volume_left

5. 收到成交信息回报时回调

def on_trade(context, trade):
    #context.log.info("[on_trade] {}".format(trade))
    code = trade.instrument_id
    sale_codes = private['trade']['sale_codes']
    buy_codes = private['trade']['buy_codes']
    
    if code in sale_codes:
        sale_codes[code]['on_ask'] -= trade.volume
    elif code in buy_codes:
        buy_codes[code]['on_bid'] -= trade.volume

6. 自定义撤单回调函数

def cancel_order(context, order_id):
    action_id = context.cancel_order(order_id)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我的小白兔奶糖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值