【OnSignal】- Bar内Buy/Sell对OnSignal事件的触发

对OnSignal事件的Bar内触发做了下测试,有点略出乎意料,贴出来一起看下,模拟多折腾,实盘少惊吓


测试说明:

- 同一根bar的onbar事件需要多次触发,建议用实盘环境,设置周期为5秒 (onBar做了QuoteStatus检查,为避免历史bar干扰)

- 在每一根bar内由第3个tick驱动第一次buy下单(Order #1), 第4个tick驱动一次下单(Order #2), OnClose事件内下一次单(Order #3),然后由OnSignal捕捉并显示


代码如下:


Params
    //此处添加参数

Vars
    Global Integer tickCounter(0);
    
Events
    
    OnInit()
    {
        PrintClear;
        
    }
    
    OnBarOpen(ArrayRef<Integer> indexes) {
    
        If(QuoteStatus <> Enum_QuoteStatus_RealTime )
            Return;
        
        tickCounter = 0;
        Print("\n *********Bar #" + Text(CurrentBar)+ " 开始*********");
    
    }

    OnBar(ArrayRef<Integer> indexs)
    {
        If(QuoteStatus <> Enum_QuoteStatus_RealTime )
            Return;
        
        tickCounter = tickCounter + 1;
        
        //输出收到tick时的本地时间
        Print(" @ Tick #" + Text(tickCounter) + " @" + DateTimeToString(CurrentDate + CurrentTime));
        
        // # Order 1: 收到第3个tick后,触发发单信号
        If(tickCounter == 3)
        {
            Print(" # Order 1 > " + DateTimeToString(CurrentDate + CurrentTime));
            Print("    > MarketPosition = " + Text(MarketPosition));
            Print("    > longCurrentContracts = " + Text(longCurrentContracts));
            Print("    > shortCurrentContracts = " + Text(shortCurrentContracts));
            Buy(1, C);            
    
        } 
        // # Order 2: 收到第4个tick后,触发发单信号
        If(tickCounter == 4)
        {
            Print(" # Order 2 > " + DateTimeToString(CurrentDate + CurrentTime));
            Print("    > MarketPosition = " + Text(MarketPosition));
            Print("    > longCurrentContracts = " + Text(longCurrentContracts));
            Print("    > shortCurrentContracts = " + Text(shortCurrentContracts));
            Buy(2, C);
            
        } 
        
    }
    
    OnBarClose(ArrayRef<Integer> indexes) {
    
        If(QuoteStatus <> Enum_QuoteStatus_RealTime )
            Return;
        
        // # Order 3: 收盘时,触发发单信号
        Print(" # Order 3 On BarClose > " + DateTimeToString(CurrentDate + CurrentTime));
        Print("    > MarketPosition = " + Text(MarketPosition));
        Print("    > longCurrentContracts = " + Text(longCurrentContracts));
        Print("    > shortCurrentContracts = " + Text(shortCurrentContracts));
        Buy(7, C);
        
    }
    
    OnSignal(ArrayRef<Signal> signals) {
        
        Integer i;
        For i = 0 To GetArraySize(signals) - 1 {
            Print("---- Singal ------ \n" + Text(signals[i]) + "\n--------------");
        }
    }


测试场景1: Order #1 , #2, #3 同为Buy,但volume不同

取其中一个Bar来检查,结果如图, Order #1触发了OnSignal, Order #2, #3均没有:


测试场景 2: 将Order #2 由Buy修改为SellShort, 需要更改的代码段如下


// # Order 2: 收到第4个tick后,触发发单信号
        If(tickCounter == 4)
        {
            Print(" # Order 2 > " + DateTimeToString(CurrentDate + CurrentTime));
            Print("    > MarketPosition = " + Text(MarketPosition));
            Print("    > longCurrentContracts = " + Text(longCurrentContracts));
            Print("    > shortCurrentContracts = " + Text(shortCurrentContracts));
            //Buy(2, C);
            SellShort(2, C);
            
        } 


测试结果如下图, Order #1和Order #2均触发了OnSignal, Order #3没有



测试场景 3: 以初始代码为基准, 在Order #1中连续做两次参数一样的Buy, 修改代码段如下


// # Order 1: 收到第3个tick后,触发发单信号
        If(tickCounter == 3)
        {
            Print(" # Order 1 > " + DateTimeToString(CurrentDate + CurrentTime));
            Print("    > MarketPosition = " + Text(MarketPosition));
            Print("    > longCurrentContracts = " + Text(longCurrentContracts));
            Print("    > shortCurrentContracts = " + Text(shortCurrentContracts));
            Buy(1, C); 
            Buy(1, C);
    
        } 
        // # Order 2: 收到第4个tick后,触发发单信号
        If(tickCounter == 4)
        {
            Print(" # Order 2 > " + DateTimeToString(CurrentDate + CurrentTime));
            Print("    > MarketPosition = " + Text(MarketPosition));
            Print("    > longCurrentContracts = " + Text(longCurrentContracts));
            Print("    > shortCurrentContracts = " + Text(shortCurrentContracts));
            Buy(2, C);
            //SellShort(2, C);
            
        } 


测试结果如下: Order #1的Buy触发了两次OnSignal, Order #2和Order #3都没触发



测试场景4: 基于最初的代码,将OnClose中的Order #3改为SellShort

修改代码如下:


OnBar(ArrayRef<Integer> indexs)
    {
        If(QuoteStatus <> Enum_QuoteStatus_RealTime )
            Return;
        
        tickCounter = tickCounter + 1;
        
        //输出收到tick时的本地时间
        Print(" @ Tick #" + Text(tickCounter) + " @" + DateTimeToString(CurrentDate + CurrentTime));
        
        // # Order 1: 收到第3个tick后,触发发单信号
        If(tickCounter == 3)
        {
            Print(" # Order 1 > " + DateTimeToString(CurrentDate + CurrentTime));
            Print("    > MarketPosition = " + Text(MarketPosition));
            Print("    > longCurrentContracts = " + Text(longCurrentContracts));
            Print("    > shortCurrentContracts = " + Text(shortCurrentContracts));
            Buy(1, C); 
            
        } 
        // # Order 2: 收到第4个tick后,触发发单信号
        If(tickCounter == 4)
        {
            Print(" # Order 2 > " + DateTimeToString(CurrentDate + CurrentTime));
            Print("    > MarketPosition = " + Text(MarketPosition));
            Print("    > longCurrentContracts = " + Text(longCurrentContracts));
            Print("    > shortCurrentContracts = " + Text(shortCurrentContracts));
            Buy(2, C);
            
        } 
        
    }
    
    OnBarClose(ArrayRef<Integer> indexes) {
    
        If(QuoteStatus <> Enum_QuoteStatus_RealTime )
            Return;
        
        // # Order 3: 收盘时,触发发单信号
        Print(" # Order 3 On BarClose > " + DateTimeToString(CurrentDate + CurrentTime));
        Print("    > MarketPosition = " + Text(MarketPosition));
        Print("    > longCurrentContracts = " + Text(longCurrentContracts));
        Print("    > shortCurrentContracts = " + Text(shortCurrentContracts));
        SellShort(7, C);
        
    }


测试结果如下:Order #1和Order #3触发了OnSignal, 但是Order #2没有



测试场景 5: 以初始代码为基准,将Order #1的操作改为先Buy然后马上SellShort (注意与测试场景2对比)

需要修改的代码如下:


// # Order 1: 收到第3个tick后,触发发单信号
        If(tickCounter == 3)
        {
            Print(" # Order 1 > " + DateTimeToString(CurrentDate + CurrentTime));
            Print("    > MarketPosition = " + Text(MarketPosition));
            Print("    > longCurrentContracts = " + Text(longCurrentContracts));
            Print("    > shortCurrentContracts = " + Text(shortCurrentContracts));
            Buy(1, C); 
            SellShort(2, C); 
            
        } 

测试结果如下图: Order #1触发了三次OnSignal, 开多,平多,开空,无论MarketPosition是0还是1

而在测试场景2中,虽然MarketPosition也是1, 但SellShort只是做了开空操作。


以上所有测试场景Order #1和Order #2都引起了信号闪烁, 只有Order #3在虚拟账号上成功建多仓。


观察与总结:

1. 似乎在同一个Bar内只要一种类型的下单指令如Buy,只有在驱动事件执行的第一次才会触发OnSignal, 之后哪怕参数不同再次执行也不会触发。(原以为参数不同会被认为是新的不同的报单,也会触发OnSignal)

2. (测试场景 3)在Bar内执行第一次下单操作,哪怕有两个参数一样的相同操作,都会连续触发OnSignal

3.(测试场景5)这个跟(测试场景2)中sellshort表现不同应该跟SetTradeSide的值不同有关,默认是0, 改为1后两个测试场景sellshort行为一致,但是跟marketposition的值无关,跟文档中的描述不太一致。


问题:

1. 在一个bar内,buy/sell/buytocover/sellshort这四个函数除非在一次事件执行中连续调用,否则每个只能触发一次onsignal?

2. 按照文档,当marketposition的值不同的时候, sellshort的行为会有所不同,但是场景2与5中marketposition=1, 为何会有不同?另外在场景5中,无论marketposition是0还是1,sellshort的行为为何又相同?




onsignal域问题
onsignal域
【OnSignal域】- 如何区分平今还是平昨
关于onsignal控制账户交易的问题
OnSignal事件域不能成交,如何映射到主力合约?
A函数在Onsignal下面发单需要全局变量控制次数吗
用buy函数无法触发onorder,onfill等类似事件么?
OnSignal的comoffset在用A函数发送委托时能够自动适应合约的平仓 平今或者平昨吗?
看期货指数确定买卖平仓点,发现在期权合约的k线数据与期货指数不能够同步,onSignal未能同步下单
【新手求教】关于TB回测时Bar内路径模拟与Tick级信号触发的疑问

内容太多了。。。

1 同一条件 只触发一次 和条件有关 和参数无关

2 同一条件内 连续的买卖 连续触发

3 TradeSide当然会影响


其他没有时间详细看

提醒一点:

按照你的代码排列顺序

当前Bar打印的各种值 都是上个bar的值



确实有点多,发之前也在犹豫,反正测试也做了,发出来以来给自己留个备忘,另外也许对有类似问题的小伙伴万一有用呢。

谢谢您的提醒,这个应该解释了问题”另外在场景5中,无论marketposition是0还是1,sellshort的行为为何又相同?“,事实上我昨晚单独又做了测试,应该是调用了buy之后marketposition=1, 此后调用sellshort的行为在tradeside=0的情况下符合文档中的描述, 只是当时打印的值是之前的,所以显示marketposition=0。

对于场景2中marketposition的值是在调用sellshort前打印的,反应的就是当下的值, marketposition=1的情况下,却直接开了空单而不是先平多单再开空单,还是有些困惑。