算法示例
直接委托算法
直接发出新的委托(限价单、停止单、市价单)
- def on_tick(self, tick: TickData):
- """"""
- if not self.vt_orderid:
- if self.direction == Direction.LONG:
- self.vt_orderid = self.buy(
- self.vt_symbol,
- self.price,
- self.volume,
- self.order_type,
- self.offset
- )
- else:
- self.vt_orderid = self.sell(
- self.vt_symbol,
- self.price,
- self.volume,
- self.order_type,
- self.offset
- )
- self.put_variables_event()
时间加权平均算法
将委托数量平均分布在某个时间区域内;
每隔一段时间用指定的价格挂出买单(或者卖单)。
买入情况:买一价低于目标价格时,发出委托,委托数量在剩余委托量与委托分割量中取最小值。
卖出情况:卖一价高于目标价格时,发出委托,委托数量在剩余委托量与委托分割量中取最小值。
- 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
- )
网格算法
每隔一段时间检查委托情况,若有委托则先清空。
基于用户设置的价格步进(即网格)计算目标距离,目标距离=(目标价格- 当前价格)/价格步进,故当前价格低于目标价格,目标距离为正,方向为买入;当前价格高于目标价格,目标距离为负,方向为卖出。(高抛低吸概念)
计算目标仓位,目标仓位= 取整后的目标距离 * 委托数量步进。注意卖卖方向取整的方式是不同的:买入方向要向下取整math.floor(),如目标距离为1.6,取1;卖出方向要向上取整,如目标距离为-1.6,取-1。
计算具体委托仓位:若目标买入仓位大于当前仓位,执行买入操作;若目标卖出仓位低于当前仓位,执行卖出操作。
为了能够快速成交,买入情况是基于ask price计算,卖出情况是基于bid price计算。
- def on_timer(self):
- """"""
- if not self.last_tick:
- return
- self.timer_count += 1
- if self.timer_count < self.interval:
- self.put_variables_event()
- return
- self.timer_count = 0
- if self.vt_orderid:
- self.cancel_all()
- # Calculate target volume to buy
- target_buy_distance = (self.price - self.last_tick.ask_price_1) / self.step_price
- target_buy_position = math.floor(target_buy_distance) * self.step_volume
- target_buy_volume = target_buy_position - self.last_pos
- # Buy when price dropping
- if target_buy_volume > 0:
- self.vt_orderid = self.buy(
- self.vt_symbol,
- self.last_tick.ask_price_1,
- min(target_buy_volume, self.last_tick.ask_volume_1)
- )
- # Calculate target volume to sell
- target_sell_distance = (self.price - self.last_tick.bid_price_1) / self.step_price
- target_sell_position = math.ceil(target_sell_distance) * self.step_volume
- target_sell_volume = self.last_pos - target_sell_position
- # Sell when price rising
- if target_sell_volume > 0:
- self.vt_orderid = self.sell(
- self.vt_symbol,
- self.last_tick.bid_price_1,
- min(target_sell_volume, self.last_tick.bid_volume_1)
- )
套利算法
每隔一段时间检查委托情况,若有委托则先清空;若主动腿还持有净持仓,通过被动腿成交来对冲。
计算价差spread_bid_price 和 spread_ask_price, 以及对应的委托数量
卖出情况:主动腿价格相对被动腿上涨,其价差spread_bid_price大于spread_up时,触发买入信号
买入情况:主动腿价格相对被动腿下跌,其价差spread_ask_price小于 - spread_down(spread_down默认设置为正数)时,触发卖出信号
在买卖信号判断加入最大持仓的限制,其作用是避免持仓过多导致保证金不足或者直接被交易所惩罚性强平;而且随着价差持续波动,主动腿持仓可以从0 -> 10 -> 0 -> -10 -> 0,从而实现平仓获利离场。
- def on_timer(self):
- """"""
- self.timer_count += 1
- if self.timer_count < self.interval:
- self.put_variables_event()
- return
- self.timer_count = 0
- if self.active_vt_orderid or self.passive_vt_orderid:
- self.cancel_all()
- return
- if self.net_pos:
- self.hedge()
- return
- active_tick = self.get_tick(self.active_vt_symbol)
- passive_tick = self.get_tick(self.passive_vt_symbol)
- if not active_tick or not passive_tick:
- return
- # Calculate spread
- spread_bid_price = active_tick.bid_price_1 - passive_tick.ask_price_1
- spread_ask_price = active_tick.ask_price_1 - passive_tick.bid_price_1
- spread_bid_volume = min(active_tick.bid_volume_1, passive_tick.ask_volume_1)
- spread_ask_volume = min(active_tick.ask_volume_1, passive_tick.bid_volume_1)
- # Sell condition
- if spread_bid_price > self.spread_up:
- if self.acum_pos <= -self.max_pos:
- return
- else:
- self.active_vt_orderid = self.sell(
- self.active_vt_symbol,
- active_tick.bid_price_1,
- spread_bid_volume
- )
- # Buy condition
- elif spread_ask_price < -self.spread_down:
- if self.acum_pos >= self.max_pos:
- return
- else:
- self.active_vt_orderid = self.buy(
- self.active_vt_symbol,
- active_tick.ask_price_1,
- spread_ask_volume
- )
- self.put_variables_event()
- def hedge(self):
- """"""
- tick = self.get_tick(self.passive_vt_symbol)
- volume = abs(self.net_pos)
- if self.net_pos > 0:
- self.passive_vt_orderid = self.sell(
- self.passive_vt_symbol,
- tick.bid_price_5,
- volume
- )
- elif self.net_pos < 0:
- self.passive_vt_orderid = self.buy(
- self.passive_vt_symbol,
- tick.ask_price_5,
- volume
- )
- def on_trade(self, trade: TradeData):
- """"""
- # Update net position volume
- if trade.direction == Direction.LONG:
- self.net_pos += trade.volume
- else:
- self.net_pos -= trade.volume
- # Update active symbol position
- if trade.vt_symbol == self.active_vt_symbol:
- if trade.direction == Direction.LONG:
- self.acum_pos += trade.volume
- else:
- self.acum_pos -= trade.volume
- # Hedge if active symbol traded
- if trade.vt_symbol == self.active_vt_symbol:
- self.hedge()
- self.put_variables_event()