VeighNa量化社区
你的开源社区量化交易平台
Member
加入于:
帖子: 158
声望: 71

这个是一个常见需求,按照策略实例记录交易条目和损益。整体的损益可以通过第三方行情软件来分析,如果有多个CTA策略实例(策略-品种-参数组合实例),如何对每个策略实例记录交易条目和损益情况。

下面代码是在vntrader 2.6 级别的实例代码,并不完全,因为改动比较多,这个仅仅是一个思路的示例。

先简单介绍下思路,记录分为3个部分,一个是新建触发停止单对象加入触发价,首单价和成交均价信息,二个把完成的触发停止单和对应的交易单保存到数据库,第三个根据每次offset的触发停止单,平仓价格数量和开仓触发停止单的开方价格数量,统计出当前的历史平仓总收益,如果没平仓就是当前价格的开仓收益,保存到json或者数据库都可以。

首先, cta_strategy/base.py 中增加一个新的event类型 EVENT_CTA_TRIGGERED_STOPORDER,用做触发的stop order事件

EVENT_CTA_TRIGGERED_STOPORDER = 'eCtaTriggeredStopOrder'

在 cta_strategy/ engine.py 中,在方法 check_stop_order加入下面代码, 这个代码是创建一个新的对象triggered_stop_order,是一个触发的stop order, 加入已成交笔数,触发价,首单价和成交均价信息。

# Update stop order status if placed successfully
if vt_orderids:
    # Remove from relation map.
    if vt_orderids == 1:
        self.write_log(f"取消挂单,{strategy.strategy_name} {stop_order.stop_orderid}")
        self.cancel_order(strategy,stop_order.stop_orderid)
        return
    self.stop_orders.pop(stop_order.stop_orderid)
    strategy_vt_orderids = self.strategy_orderid_map[strategy.strategy_name]
    if stop_order.stop_orderid in strategy_vt_orderids:
        strategy_vt_orderids.remove(stop_order.stop_orderid)
    # Change stop order status to cancelled and update to strategy.
    stop_order.status = StopOrderStatus.TRIGGERED
    stop_order.vt_orderids = vt_orderids
    # Billy add to triggerred_stop_order dict
    triggered_stop_order = copy(stop_order)
    # triggered_stop_order.vt_orderids = list(map(lambda name: name.split(".")[1], triggered_stop_order.vt_orderids))
    triggered_stop_order.stop_orderid = triggered_stop_order.stop_orderid + "." + stop_order.strategy_name + "." + '.'.join(
        vt_orderids)
    triggered_stop_order.datetime = copy(tick.datetime)
    triggered_stop_order.completed_volume = 0
    triggered_stop_order.average_price = 0
    triggered_stop_order.first_price = 0
    triggered_stop_order.triggered_price = tick.last_price
    for vt_orderid in vt_orderids:
        self.vt_orderid_triggered_stop_order[vt_orderid] = triggered_stop_order
    # end Billy add
    self.call_strategy_func(
        strategy, strategy.on_stop_order, stop_order
    )
    self.put_stop_order_event(stop_order)

在方法process_trade_event, 加入下面代码,这段代码是根据在triggered_stop_order中记录的真实交易单号,如果返回的交易信息属于这个triggered_stop_order,那么记录成交数量,成交价格,算出平均价格,并且把这个trade信息保存到数据。这个保存时候把 triggered_stop_order的id放到 trade里面,方便日后关联

如果搜到的真实交易单的累计笔数和挂单笔数一致,说明挂单已经完成状态,把 triggered_stop_order放入数据

# Update strategy pos before calling on_trade method
if trade.direction == Direction.LONG:
    strategy.pos += trade.volume
else:
    strategy.pos -= trade.volume
self.call_strategy_func(strategy, strategy.on_trade, trade)
# Billy added, update triggered_stop_order
cta_trade = copy(trade)
allComplete = False
if cta_trade.vt_orderid in self.vt_orderid_triggered_stop_order.keys():
    triggered_stop_order = self.vt_orderid_triggered_stop_order[cta_trade.vt_orderid]
    if triggered_stop_order.first_price == 0:
        triggered_stop_order.first_price = cta_trade.price
    triggered_stop_order.completed_volume += cta_trade.volume
    triggered_stop_order.average_price += cta_trade.volume * cta_trade.price
    # change orderid to stop_orderid
    cta_trade.orderid = triggered_stop_order.stop_orderid
    # current_triggered_stop_order = triggered_stop_order
    if triggered_stop_order.completed_volume == triggered_stop_order.volume:
        allComplete = True
self.call_strategy_func(strategy, strategy.on_cta_trade, cta_trade)
if allComplete:
    # Sync strategy variables to data file
    self.sync_strategy_data(strategy)
    triggered_stop_order.average_price = round(
        triggered_stop_order.average_price / triggered_stop_order.completed_volume, 2)
    self.put_cta_triggered_stoporder_event(triggered_stop_order)
    database_manager.save_triggered_stop_order_data(copy(triggered_stop_order))
    for k in triggered_stop_order.vt_orderids:
        self.vt_orderid_triggered_stop_order.pop(k)
    self.call_strategy_func(strategy, strategy.save_setting_file)
# Update GUI
self.put_strategy_event(strategy)

写入数据库方法这里不做累述,主要是通过event事件来触发数据库保存操作,这个显示下trade和 triggered_stop_order的数据结构示例

Trade的orderidd

{
    "_id" : ObjectId("628b9523134fcca9c87671ea"),
    "datetime" : ISODate("2022-05-23T22:07:31.000Z"),
    "strategy" : "oneBar",
    "symbol" : "rb2210",
    "tradeid" : "       78259",
    "exchange" : "SHFE",
    "orderid" : "STOP.4.oneBar.CTP.3_-1818434211_2",
    "direction" : "空",
    "offset" : "开",
    "price" : 4594.0,
    "volume" : 1.0,
    "date" : ISODate("2022-05-23T00:00:00.000Z")
}

对应的triggered_stop_order,

{
    "_id" : ObjectId("628b9523134fcca9c87671ec"),
    "datetime" : ISODate("2022-05-23T22:07:31.500Z"),
    "stop_orderid" : "STOP.4.oneBar.CTP.3_-1818434211_2",
    "strategy_name" : "oneBar",
    "vt_symbol" : "rb2210.SHFE",
    "direction" : "空",
    "offset" : "开",
    "price" : 4594.0,
    "volume" : 1.0,
    "lock" : false,
    "net" : false,
    "vt_orderids" : [ 
        "CTP.3_-1818434211_2"
    ],
    "status" : "已触发",
    "completed_volume" : 1.0,
    "average_price" : 4594.0,
    "first_price" : 4594.0,
    "triggered_price" : 4594.0
}

至于之后查询很多方法,可以用第三方分析软件,也可以简单做个页面。

至于损益的分析,可以 根据每次offset的触发停止单,平仓价格数量和开仓触发停止单的开方价格数量,统计出当前的历史平仓总收益,如果没平仓就是当前价格的开仓收益,保存到json或者数据库都可以。

这里要注意的是移仓操作,可能对导致开平仓交易对对上。所以在移仓也要做对应的增强。具体我后面写一下增强的移仓代码

Member
avatar
加入于:
帖子: 1474
声望: 105

感谢分享!!!

Member
avatar
加入于:
帖子: 260
声望: 3

谢谢大佬,咨询一下,self.call_strategy_func(strategy, strategy.on_cta_trade, cta_trade)是在策略里面定义的什么呢?另外如下图所示,建仓4次,为什么平均建仓价格都是最后一次建仓的价格呢?

description

© 2015-2022 上海韦纳软件科技有限公司
备案服务号:沪ICP备18006526号

沪公网安备 31011502017034号

【用户协议】
【隐私政策】
【免责条款】