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

给回测K线图表增加自定义交易标记

效果图

description

用法

在cta策略中的buy等下单函数中,增加一个str类型的mark入参,作为自定义标记,即可在回测K线图上看到自定义的标记

self.buy(bar.high_price+30,self.fixed_size,mark="买点")

涉及修改的文件

  • vnpy.app.cta_strategy.template.py
  • vnpy.app.cta_strategy.backtesting.py
  • vnpy.trader.object.py
  • vnpy.app.cta_strategy.base.py
  • vnpy.app.cta_backtester.ui.widget.py

在K线图表中绘制标记字段

vnpy.app.cta_backtester.ui.widget.BacktesterManager.show_candle_chart()函数绘制K线图及交易标记,我们要修改的是交易标记。
trades数据需要回测引擎提供

绘制由vnpy.app.cta_strategy.ui.widget.CandleChartDialog.update_trades()实现,参照原来的volume交易数量绘制格式,补充交易标记绘制即可

# 交易标记
            openmark = d["open_mark"]
            closemark = d["close_mark"]
            if len(openmark)>0:
                text_color = QtGui.QColor(scatter_color)
                openmark_text = pg.TextItem(f"[{openmark}]", color=text_color, anchor=(0.5, 0.5))

                openmark_text.setPos(open_ix, open_y - open_side * y_adjustment * 6)

                self.items.append(openmark_text)

                candle_plot.addItem(openmark_text)

            if len(closemark)>0:
                text_color = QtGui.QColor(scatter_color)
                closemark_text = pg.TextItem(f"[{closemark}]", color=text_color, anchor=(0.5, 0.5))

                closemark_text.setPos(close_ix, close_y - close_side * y_adjustment * 6)

                self.items.append(closemark_text)

                candle_plot.addItem(closemark_text)

update_trades()中的trade_pairs由generate_trade_pairs()生成,故还需要修改generate_trade_pairs()函数

d = {
                "open_dt": open_trade.datetime,
                "open_price": open_trade.price,
                "close_dt": trade.datetime,
                "close_price": trade.price,
                "direction": open_trade.direction,
                "volume": close_volume,
                "open_mark": open_trade.mark,
                "close_mark": trade.mark
            }

在回测引擎中增加标记字段

vnpy.app.cta_strategy.ui.widget.BacktesterManager.show_candle_chart()---->
vnpy.app.cta_backtester.engine.BacktestEngine.get_all_trades()---->
vnpy.app.cta_strategy.backtesting.BacktestingEngine.get_all_trades()---->
vnpy.app.cta_strategy.backtesting.BacktestingEngine.trades

需要在self.trades字典的values中增加字段
而给self.trades字典增加trade元素的有两个函数cross_limit_order()、cross_stop_order()
修改这两个函数即可(增加标记字段)

cross_limit_order()

trade = TradeData(
                symbol=order.symbol,
                exchange=order.exchange,
                orderid=order.orderid,
                tradeid=str(self.trade_count),
                direction=order.direction,
                offset=order.offset,
                price=trade_price,
                volume=order.volume,
                datetime=self.datetime,
                gateway_name=self.gateway_name,
                mark=order.mark
            )

cross_stop_order()

order = OrderData(
                symbol=self.symbol,
                exchange=self.exchange,
                orderid=str(self.limit_order_count),
                direction=stop_order.direction,
                offset=stop_order.offset,
                price=stop_order.price,
                volume=stop_order.volume,
                traded=stop_order.volume,
                status=Status.ALLTRADED,
                gateway_name=self.gateway_name,
                datetime=self.datetime,
                mark = stop_order.mark
            )

            trade = TradeData(
                symbol=order.symbol,
                exchange=order.exchange,
                orderid=order.orderid,
                tradeid=str(self.trade_count),
                direction=order.direction,
                offset=order.offset,
                price=trade_price,
                volume=order.volume,
                datetime=self.datetime,
                gateway_name=self.gateway_name,
                mark = order.mark
            )

两个函数中trade数据都来自order
而order又来自self.active_limit_orders和self.active_stop_orders两个字典

给self.active_limit_orders字典增加order元素的函数是send_limit_order()
给self.active_stop_orders字典增加order元素的函数是send_stop_order()
需要修改这send_limit_order(),send_stop_order()两个函数以增加标记字段,并给vnpy.trader.object.OrderData,vnpy.trader.object.TradeData,vnpy.app.cta_strategy.base.StopOrder增加字段mark。

class OrderData(BaseData):
    """
    Order data contains information for tracking lastest status
    of a specific order.
    """

    symbol: str
    exchange: Exchange
    orderid: str

    type: OrderType = OrderType.LIMIT
    direction: Direction = None
    offset: Offset = Offset.NONE
    price: float = 0
    volume: float = 0
    traded: float = 0
    status: Status = Status.SUBMITTING
    datetime: datetime = None
    reference: str = ""
    mark: str = ""

class TradeData(BaseData):
    """
    Trade data contains information of a fill of an order. One order
    can have several trade fills.
    """

    symbol: str
    exchange: Exchange
    orderid: str
    tradeid: str
    direction: Direction = None

    offset: Offset = Offset.NONE
    price: float = 0
    volume: float = 0
    datetime: datetime = None
    mark: str = ""
def send_limit_order(
        self,
        direction: Direction,
        offset: Offset,
        price: float,
        volume: float,
        mark: str
    ):
        """"""
        self.limit_order_count += 1

        order = OrderData(
            symbol=self.symbol,
            exchange=self.exchange,
            orderid=str(self.limit_order_count),
            direction=direction,
            offset=offset,
            price=price,
            volume=volume,
            status=Status.SUBMITTING,
            gateway_name=self.gateway_name,
            datetime=self.datetime,
            mark=mark
        )

        self.active_limit_orders[order.vt_orderid] = order
        self.limit_orders[order.vt_orderid] = order

        return order.vt_orderid
def send_stop_order(
        self,
        direction: Direction,
        offset: Offset,
        price: float,
        volume: float,
        mark: str
    ):
        """"""
        self.stop_order_count += 1

        stop_order = StopOrder(
            vt_symbol=self.vt_symbol,
            direction=direction,
            offset=offset,
            price=price,
            volume=volume,
            stop_orderid=f"{STOPORDER_PREFIX}.{self.stop_order_count}",
            strategy_name=self.strategy.strategy_name,
            mark=mark
        )

        self.active_stop_orders[stop_order.stop_orderid] = stop_order
        self.stop_orders[stop_order.stop_orderid] = stop_order

        return stop_order.stop_orderid

调用send_limit_order(),send_stop_order()这两个函数的函数是send_order()函数
即也需要修改send_order()函数

def send_order(
        self,
        strategy: CtaTemplate,
        direction: Direction,
        offset: Offset,
        price: float,
        volume: float,
        stop: bool,
        lock: bool,
        mark: str = ""
    ):
        """"""
        price = round_to(price, self.pricetick)
        if stop:
            vt_orderid = self.send_stop_order(direction, offset, price, volume ,mark)
        else:
            vt_orderid = self.send_limit_order(direction, offset, price, volume ,mark)
        return [vt_orderid]

回测引擎中的send_order()函数被CTA策略调用
需要修改vnpy.app.cta_strategy.template.CtaTemplate策略模板中的buy()、sell()、short()、cover()、send_order()函数

def buy(self, price: float, volume: float, stop: bool = False, lock: bool = False, mark: str = ""):
        """
        Send buy order to open a long position.
        """
        return self.send_order(Direction.LONG, Offset.OPEN, price, volume, stop, lock, mark)

在实盘引擎中忽略新增的标记字段

因为实盘引擎中也有send_order()函数,且在实盘时也被调用,所以要对额外的标记字段做忽略处理
为了简化修改,也不想动实盘引擎减少风险,所以这个修改也在vnpy.app.cta_strategy.template.CtaTemplate策略模板中实现,修改send_order()函数
即根据EngineType区分

def send_order(
        self,
        direction: Direction,
        offset: Offset,
        price: float,
        volume: float,
        stop: bool = False,
        lock: bool = False,
        mark: str = "" # 增加标记字段
    ):
        """
        Send a new order.
        """

        if self.trading:
            engine_Type = self.get_engine_type()
            if engine_Type == EngineType.BACKTESTING:
                vt_orderids = self.cta_engine.send_order(
                    self, direction, offset, price, volume, stop, lock, mark
                )
            else:
                vt_orderids = self.cta_engine.send_order(
                    self, direction, offset, price, volume, stop, lock
                )

            return vt_orderids
        else:
            return []
Administrator
avatar
加入于:
帖子: 4501
声望: 321

给你加个精华

Member
avatar
加入于:
帖子: 23
声望: 0

膜拜大神。

Member
加入于:
帖子: 3
声望: 0

请教一下楼主 我的2.4版本没有这个文件vnpy.app.cta_backtester.ui.widget.BacktesterManager.show_candle_chart() ,请问您是那个版本vnpy,谢谢

Member
avatar
加入于:
帖子: 4666
声望: 285

去剥离后的路径vnpy_ctastrategy下找找吧

Member
avatar
加入于:
帖子: 227
声望: 0

第一步:绘制由vnpy.app.cta_strategy.ui.widget.CandleChartDialog.update_trades()实现,参照原来的volume交易数量绘制格式,补充交易标记绘制即可。
这个第一步就没找到

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

沪公网安备 31011502017034号

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