vnpy/docs/algo_trader.md
2019-05-17 14:57:53 +08:00

12 KiB
Raw Blame History

算法交易

算法交易一般用于把巨型单子拆分成一个个小单,能够有效降低交易成本,冲击成本等。

 

模块构成

算法交易模块主要由4部分构成如下图

  • engine定义了算法引擎其中包括引擎初始化、保存/移除/加载算法配置、启动算法、停止算法、订阅行情、挂撤单等。
  • template定义了交易算法模板具体的算法示例如冰山算法都需要继承于该模板。
  • algos官方提供的交易算法示例包括冰山算法、狙击手算法、时间加权平均算法、条件委托、最优限价。
  • ui基于PyQt5的GUI图形应用。

 

基本操作

在VN Trader的菜单栏中点击“功能”—>“算法交易”即可打开如图算法交易模块窗口,如下图。

算法交易模块有2部分构成

  • 委托交易,用于启动算法交易;
  • 数据监控,用于监控算法交易执行情况,并且能够手动停止算法。

 

委托交易

下面以时间加权平均算法为例,具体介绍如下图委托交易功能选项。

  • 算法目前提供了5种交易算法时间加权平均算法、冰山算法、狙击手算法、条件委托、最优限价
  • 本地代码vt_symbol格式如AAPL.SMART, 用于算法交易组建订阅行情和委托交易;
  • 方向:做多或者做空;
  • 价格:委托下单的价格;
  • 数量:委托的总数量,需要拆分成小单进行交易;
  • 执行时间:运行改算法交易的总时间,以秒为单位;
  • 每轮间隔:每隔一段时间(秒)进行委托下单操作;
  • 启动算法:设置好算法配置后,用于立刻执行算法交易。

所以该算法执行的任务如下通过时间加权平均算法买入10000股AAPL美股执行价格为180美金执行时间为600秒间隔为6秒即每隔6秒钟当买一价少于等于180时以180的价格买入100股AAPL买入操作分割成100次。

交易配置可以保存在json文件这样每次打开算法交易模块就不用重复输入配置。其操作是在“算法名称”选项输入该算法设置命名然后点击下方"保存设置”按钮。保存的json文件在C:\Users\Administrator\.vntrader文件夹的algo_trading_setting.json中如图。

委托交易界面最下方的“全部停止”按钮用于一键停止所有执行中的算法交易。

 

数据监控

数据监控由4个部分构成。

  • 活动组件:显示正在运行的算法交易,包括:算法名称、参数、状态。最右边的“停止”按钮用于手动停止执行中的算法。

 

  • 历史委托组件:显示已完成的算法交易,同样包括:算法名称、参数、状态。

 

  • 日志组件:显示启动、停止、完成算法的相关日志信息。在打开算法交易模块后,会进行初始化,故日志上会首先显示“算法交易引擎启动”和“算法配置载入成功”。

 

  • 配置组件用于载入algo_trading_setting.json的配置信息并且以图形化界面显示出来。 用户可以点击“使用”按钮立刻读取配置信息,并显示在委托交易界面上,点击“启动算法”即可开始进行交易; 用户也可以点击“移除”按钮来移除该算法配置同步更新到json文件内。

 

算法示例

时间加权平均算法

  • 将委托数量平均分布在某个时间区域内;
  • 每隔一段时间用指定的价格挂出买单(或者卖单)。
  • 买入情况:买一价低于目标价格时,发出委托,委托数量在剩余委托量与委托分割量中取最小值。
  • 卖出情况:卖一价高于目标价格时,发出委托,委托数量在剩余委托量与委托分割量中取最小值。
    def on_timer(self):
        """"""
        self.timer_count += 1
        self.total_count += 1
        self.put_variables_event()

        if self.total_count >= self.time:
            self.write_log("执行时间已结束,停止算法")
            self.stop()
            return

        if self.timer_count < self.interval:
            return
        self.timer_count = 0

        tick = self.get_tick(self.vt_symbol)
        if not tick:
            return

        self.cancel_all()

        left_volume = self.volume - self.traded
        order_volume = min(self.order_volume, left_volume)

        if self.direction == Direction.LONG:
            if tick.ask_price_1 <= self.price:
                self.buy(self.vt_symbol, self.price,
                         order_volume, offset=self.offset)
        else:
            if tick.bid_price_1 >= self.price:
                self.sell(self.vt_symbol, self.price,
                          order_volume, offset=self.offset)

 

冰山算法

  • 在某个价位挂单,但是只挂一部分,直到全部成交。
  • 买入情况先检查撤单最新Tick卖一价低于目标价格执行撤单若无活动委托发出委托委托数量在剩余委托量与挂出委托量中取最小值。
  • 卖出情况先检查撤单最新Tick买一价高于目标价格执行撤单若无活动委托发出委托委托数量在剩余委托量与挂出委托量中取最小值。
    def on_timer(self):
        """"""
        self.timer_count += 1

        if self.timer_count < self.interval:
            self.put_variables_event()
            return

        self.timer_count = 0

        contract = self.get_contract(self.vt_symbol)
        if not contract:
            return

        # If order already finished, just send new order
        if not self.vt_orderid:
            order_volume = self.volume - self.traded
            order_volume = min(order_volume, self.display_volume)

            if self.direction == Direction.LONG:
                self.vt_orderid = self.buy(
                    self.vt_symbol,
                    self.price,
                    order_volume,
                    offset=self.offset
                )
            else:
                self.vt_orderid = self.sell(
                    self.vt_symbol,
                    self.price,
                    order_volume,
                    offset=self.offset
                )
        # Otherwise check for cancel
        else:
            if self.direction == Direction.LONG:
                if self.last_tick.ask_price_1 <= self.price:
                    self.cancel_order(self.vt_orderid)
                    self.vt_orderid = ""
                    self.write_log(u"最新Tick卖一价低于买入委托价格之前委托可能丢失强制撤单")
            else:
                if self.last_tick.bid_price_1 >= self.price:
                    self.cancel_order(self.vt_orderid)
                    self.vt_orderid = ""
                    self.write_log(u"最新Tick买一价高于卖出委托价格之前委托可能丢失强制撤单")

        self.put_variables_event()

 

狙击手算法

  • 监控最新tick推送的行情发现好的价格立刻报价成交。
  • 买入情况最新Tick卖一价低于目标价格时发出委托委托数量在剩余委托量与卖一量中取最小值。
  • 卖出情况最新Tick买一价高于目标价格时发出委托委托数量在剩余委托量与买一量中取最小值。
    def on_tick(self, tick: TickData):
        """"""
        if self.vt_orderid:
            self.cancel_all()
            return

        if self.direction == Direction.LONG:
            if tick.ask_price_1 <= self.price:
                order_volume = self.volume - self.traded
                order_volume = min(order_volume, tick.ask_volume_1)

                self.vt_orderid = self.buy(
                    self.vt_symbol,
                    self.price,
                    order_volume,
                    offset=self.offset
                )
        else:
            if tick.bid_price_1 >= self.price:
                order_volume = self.volume - self.traded
                order_volume = min(order_volume, tick.bid_volume_1)

                self.vt_orderid = self.sell(
                    self.vt_symbol,
                    self.price,
                    order_volume,
                    offset=self.offset
                )

        self.put_variables_event()

 

条件委托算法

  • 监控最新tick推送的行情发现行情突破立刻报价成交。
  • 买入情况Tick最新价高于目标价格时发出委托委托价为目标价格加上超价。
  • 卖出情况Tick最新价低于目标价格时发出委托委托价为目标价格减去超价。
    def on_tick(self, tick: TickData):
        """"""
        if self.vt_orderid:
            return

        if self.direction == Direction.LONG:
            if tick.last_price >= self.stop_price:
                price = self.stop_price + self.price_add

                if tick.limit_up:
                    price = min(price, tick.limit_up)

                self.vt_orderid = self.buy(
                    self.vt_symbol,
                    price,
                    self.volume,
                    offset=self.offset
                )
                self.write_log(f"停止单已触发,代码:{self.vt_symbol},方向:{self.direction}, 价格:{self.stop_price},数量:{self.volume},开平:{self.offset}")                   

        else:
            if tick.last_price <= self.stop_price:
                price = self.stop_price - self.price_add
                
                if tick.limit_down:
                    price = max(price, tick.limit_down)

                self.vt_orderid = self.buy(
                    self.vt_symbol,
                    price,
                    self.volume,
                    offset=self.offset
                )
                self.write_log(f"停止单已触发,代码:{self.vt_symbol},方向:{self.direction}, 价格:{self.stop_price},数量:{self.volume},开平:{self.offset}") 

        self.put_variables_event()

 

最优限价算法

  • 监控最新tick推送的行情发现好的价格立刻报价成交。
  • 买入情况先检查撤单最新Tick买一价不等于目标价格时执行撤单若无活动委托发出委托委托价格为最新Tick买一价委托数量为剩余委托量。
  • 卖出情况先检查撤单最新Tick买一价不等于目标价格时执行撤单若无活动委托发出委托委托价格为最新Tick卖一价委托数量为剩余委托量。
    def on_tick(self, tick: TickData):
        """"""
        self.last_tick = tick

        if self.direction == Direction.LONG:
            if not self.vt_orderid:
                self.buy_best_limit()
            elif self.order_price != self.last_tick.bid_price_1:
                self.cancel_all()
        else:
            if not self.vt_orderid:
                self.sell_best_limit()
            elif self.order_price != self.last_tick.ask_price_1:
                self.cancel_all()

        self.put_variables_event()

    def buy_best_limit(self):
        """"""
        order_volume = self.volume - self.traded
        self.order_price = self.last_tick.bid_price_1
        self.vt_orderid = self.buy(
            self.vt_symbol,
            self.order_price,
            order_volume,
            offset=self.offset
        )        

    def sell_best_limit(self):
        """"""
        order_volume = self.volume - self.traded
        self.order_price = self.last_tick.ask_price_1
        self.vt_orderid = self.sell(
            self.vt_symbol,
            self.order_price,
            order_volume,
            offset=self.offset
        )