vn.py量化社区
By Traders, For Traders.
Member
avatar
加入于:
帖子: 189
声望: 40

策略里面要加上bar_volume参数

def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
    #分钟成交量
    self.bar_volume = 0
def on_bar(self, bar: BarData):
    self.bar_volume = bar.volume
cta_strategy/base.py里面修改如下:
@dataclass
class StopOrder:
    """
    本地停止单
    """
    vt_symbol: str
    direction: Direction
    offset: Offset
    price: float
    volume: float
    stop_orderid: str           #停止单你委托ID
    strategy_name: str          #策略名称
    lock: bool = False          #锁仓状态
    vt_orderids: list = field(default_factory=list)         #交易所委托单ID列表
    status: StopOrderStatus = StopOrderStatus.WAITING
    triggered_datetime: datetime = None        #停止单触发交易时间
#cta_strategy\engine.py里面修改如下
from typing import (Any, Callable, Dict,Union,List)
    def __init__(self, main_engine: MainEngine, event_engine: EventEngine):
        #冰山算法拆单参数
        self.iceberg_interval = 5            #间隔5秒
        self.iceberg_percent = 0.002    #拆单价格阈值0.2%
        self.disassemble_count = 0       # 拆单执行次数
        self.limit_vt_orderids: Dict[str,List] = defaultdict(list)
        #交易所委托单状态控制,避免仅使用limit_vt_orderids控制下单(获取委托单ID延时)重复下单
        self.order_trigger: Dict[str,bool] = defaultdict(bool)
    #--------------------------------------------------------------------------------------
    def check_stop_order(self, tick: TickData):
        """
        收到行情后处理本地停止单(满足拆单条件则使用冰山拆单否则直接发送交易所委托单)
        """
        for stop_order in list(self.stop_orders.values()):
            strategy = self.strategies[stop_order.strategy_name]
            row_tick:TickData = self.get_contract_tick(stop_order.vt_symbol)
            if row_tick:
                last_price = row_tick.last_price
            else:
                continue
            #多头停止单被触发
            long_triggered = stop_order.direction == Direction.LONG and last_price >= stop_order.price
            #空头停止单被触发      
            short_triggered = stop_order.direction == Direction.SHORT and last_price <= stop_order.price 
            if long_triggered or short_triggered:
                if not stop_order.triggered_datetime:
                    stop_order.triggered_datetime = row_tick.datetime
                contract:ContractData = self.main_engine.get_contract(stop_order.vt_symbol)
                bid_price_1 = row_tick.bid_price_1
                ask_price_1 = row_tick.ask_price_1              
                exchange_str = extract_vt_symbol(stop_order.vt_symbol)[1].value
                #BITMEX,BYBIT合约发对价1档超价2个pricetick价位
                if exchange_str in ("BITMEX","BYBIT") :
                    if stop_order.direction == Direction.LONG:
                        price = ask_price_1 + contract.pricetick * 2
                    else:
                        price = bid_price_1 - contract.pricetick * 2
                #OKEF,HUOBIF,BINANCEF合约发对价1档超价3个pricetick价位
                elif exchange_str in ("OKEF","HUOBIF","BINANCEF","OKEX","HUOBI"):
                    if stop_order.direction == Direction.LONG:
                        price = ask_price_1 + contract.pricetick * 3
                    else:
                        price =  bid_price_1 - contract.pricetick * 3                
                else:
                    #国内期货合约发对价1档超价1个pricetick价位
                    if stop_order.direction == Direction.LONG:
                        #如果卖一价有价位则发卖一价+超价pricetick,没有则挂单发买一价
                        if ask_price_1 > 9999999:
                            price = bid_price_1
                        else:
                            price = ask_price_1 + contract.pricetick * 1
                    else:
                        #如果买一价有价位则发买一价-超价pricetick,没有则挂单发卖一价                 
                        if bid_price_1 > 9999999:
                            price = ask_price_1
                        else:
                            price = bid_price_1 - contract.pricetick * 1   
                #冰山算法拆单价格阈值限制  
                price_triggered = stop_order.price * (1-self.iceberg_percent) <= last_price <= stop_order.price * (1+self.iceberg_percent)
                #时间和委托单触发条件:停止单触发后超过iceberg_interval秒和没有未成交停止单,发送所限价单
                time_triggered = (row_tick.datetime - stop_order.triggered_datetime).seconds > self.iceberg_interval and not self.limit_vt_orderids and not self.order_trigger[vt_symbol]
                #策略有bar_volume参数并且委托量大于bar_volume / 60,执行冰山算法拆单
                #拆单使用超价1档价格下单,拆单iceberg_count次,间隔iceberg_interval秒,下单价格范围:stop_order.price (1+-0.2%)
                iceberg_tiggered = hasattr(strategy,"bar_volume") and strategy.bar_volume > 0 and stop_order.volume > strategy.bar_volume / 60 and price_triggered
                if iceberg_tiggered:
                    # 根据停止单委托量计算拆单次数iceberg_count
                    if strategy.bar_volume / 60 < stop_order.volume < strategy.bar_volume / 40:
                        iceberg_count = 2
                    elif strategy.bar_volume / 40 < stop_order.volume < strategy.bar_volume / 30:
                        iceberg_count = 3
                    else:
                        iceberg_count = 4
                    #每次拆单委托量
                    disassemble_volume = round_to(stop_order.volume / iceberg_count,contract.min_volume) 
                    if stop_order.offset == Offset.OPEN:
                        if time_triggered:
                            self.disassemble_count +=1
                            #实际拆单执行次数小于预期拆单次数时,执行开仓拆单
                            if self.disassemble_count <= iceberg_count:
                                self.order_trigger[vt_symbol] = True
                                self.limit_vt_orderids[vt_symbol]= self.send_limit_order(stop_order.vt_symbol, contract, stop_order.direction, stop_order.offset, price, disassemble_volume, stop_order.lock,strategy)
                            else:
                                self.disassemble_count = 0
                                self.cancel_local_stop_order(strategy,stop_order.stop_orderid)      
                    else:
                        if time_triggered:
                            #持仓仓位大于拆单量使用拆单量下单,否则使用abs(strategy.pos)下单
                            if abs(strategy.pos) >= disassemble_volume:
                                self.order_trigger[vt_symbol] = True
                                self.limit_vt_orderids[vt_symbol]= self.send_limit_order(stop_order.vt_symbol, contract, stop_order.direction, stop_order.offset, price, disassemble_volume, stop_order.lock,strategy)
                            elif 0 < abs(strategy.pos) < disassemble_volume:
                                self.order_trigger[vt_symbol] = True
                                self.limit_vt_orderids[vt_symbol]= self.send_limit_order(stop_order.vt_symbol, contract, stop_order.direction, stop_order.offset, price, abs(strategy.pos), stop_order.lock,strategy)  
                            if not strategy.pos:
                                self.cancel_local_stop_order(strategy,stop_order.stop_orderid)                              
            else:
                if not self.limit_vt_orderids[vt_symbol] and not self.order_trigger[vt_symbol]:
                    #停止单校准委托量后直接发单
                    if stop_order.offset == Offset.OPEN:
                        self.order_trigger[vt_symbol] = True
                        self.limit_vt_orderids[vt_symbol] = self.send_limit_order(vt_symbol, contract, stop_order.direction, stop_order.offset, price, stop_order.volume, stop_order.lock,strategy,OrderType.LIMIT)
                    else:
                        self.order_trigger[vt_symbol] = True
                        self.limit_vt_orderids[vt_symbol] = self.send_limit_order(vt_symbol, contract, stop_order.direction, stop_order.offset, price, abs(strategy.pos), stop_order.lock,strategy,OrderType.LIMIT)                        
                    #直接发送停止单(未触发拆单条件)后删除已完成停止单
                    self.cancel_local_stop_order(strategy,stop_order.stop_orderid)

                if self.limit_vt_orderids[vt_symbol] and self.order_trigger[vt_symbol]:
                    #更新停止单vt_orderids
                    stop_order.status = StopOrderStatus.TRIGGERED
                    stop_order.vt_orderids = self.limit_vt_orderids[vt_symbol]
                    #推送stop_order数据到策略
                    self.call_strategy_func(strategy, strategy.on_stop_order,
                                            stop_order)
                    self.put_stop_order_event(stop_order)
                    #发送委托单后重置triggered_datetime,limit_vt_orderids[vt_symbol]
                    stop_order.triggered_datetime = None
                    self.limit_vt_orderids[vt_symbol] = []
                    self.order_trigger[vt_symbol] = False
    #------------------------------------------------------------------------------------
    def get_contract_tick(self, vt_symbol):
        """
        获取合约tick数据(last_price),买卖价量(bid_price,ask_price,bid_volume,ask_volume)等参数
        """
        return self.main_engine.get_tick(vt_symbol)
    #------------------------------------------------------------------------------------
    def process_order_event(self, event: Event):
        """
        收到委托事件推送
        """
        order = event.data

        self.offset_converter.update_order(order)

        strategy = self.orderid_strategy_map.get(order.vt_orderid, None)
        if not strategy:
            return

        # 从strategy_orderid_map移除非活动委托单
        vt_orderids = self.strategy_orderid_map[strategy.strategy_name]
        if not order.is_active():
            if order.vt_orderid in vt_orderids:
                vt_orderids.remove(order.vt_orderid)

        #停止单推送到策略on_stop_order函数
        if order.type == OrderType.STOP:
            so = StopOrder(
                vt_symbol=order.vt_symbol,
                direction=order.direction,
                offset=order.offset,
                price=order.price,
                volume=order.volume,
                stop_orderid=order.vt_orderid,
                strategy_name=strategy.strategy_name,
                status=STOP_STATUS_MAP[order.status],
                vt_orderids=[order.vt_orderid],
            )
            self.call_strategy_func(strategy, strategy.on_stop_order, so)
        # 推送到策略on_order函数
        self.call_strategy_func(strategy, strategy.on_order, order)
Member
avatar
加入于:
帖子: 189
声望: 40

拆单思路:默认参数5秒拆一次,拆单的委托量大于bar_volume/60执行拆单,下单价格范围:stop_order.price (1+-0.2%),拆单价:对价超价一个pricetick,拆单单次委托量:停止单委托量/拆单次数,最多拆4次,20秒拆完😂😂😂我只是写出来能用,好不好用就不知道了。

Member
avatar
加入于:
帖子: 189
声望: 40

本地停止单真的太好用了👍👍👍

Administrator
avatar
加入于:
帖子: 4655
声望: 266

必须加个精华

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

学习中~~~正在考虑下面这个问题的实现。
普通的30分钟趋势策略,下单不成交时,哪种处理方式合理。
1、在策略内进行精细管理(onOrder)
2、交给算法模块(。
3、人工处理一下好了。

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

沪公网安备 31011502017034号