全部 智大领峰 TBQuant功能 TBL语言 TB开户 问答专区 高手圈 其他
频繁开仓,MarketPosition一直是0
2022-01-10 14:27

Params
    Numeric dkx_k1(10);                    // 多空线
    Numeric dkx_k2(10);                    // 多空线
    Enum<String> lots_mode(["资金占比","持仓市值","固定手数"]);     // 开仓手数计算类型
    Integer fixed_lots(1);                // 固定手数
    Numeric fixed_money(100000);        // 固定市值
    Numeric money_rate(0.1);            // 资金比例,0.1=10%
    bool is_rollover(True);            // 是否还原复权前价格
    
Vars
    //此处添加变量
    Series<Numeric> dkx_a;
    Series<Numeric> dkx_b;
    Series<Numeric> dkx_d;
    bool is_over;
    bool is_under;
    bool cross_over;
    bool cross_under;
    Series<Numeric> dkxcd_diff; 
    Numeric dkxcd_avg;
    Numeric dkxcd_value;
    Integer lots_num;
    Global Integer cur_lot(0);

Defs
    Integer CalcuTradeLots()        // 交易手数计算函数
    {
        Integer myLots;
        if(lots_mode=="资金占比")
        {
            myLots = Max(1,IntPart((Portfolio_CurrentEquity*money_rate/MarginRatio)/(Open*contractunit*bigpointvalue)));
        }
        else if(lots_mode=="持仓市值")
        {
            myLots = Max(1,IntPart(fixed_money/(Open*contractunit*bigpointvalue)));
        }
        else if(lots_mode=="固定手数")
            myLots = fixed_lots;
        else 
            myLots = fixed_lots;
        return myLots;
    }
    
Events
    OnInit()
    {
        Range[0:DataCount-1]
        {
            if (is_rollover)
            {
                AddDataFlag(Enum_Data_RolloverBackWard());    //设置后复权

                AddDataFlag(Enum_Data_RolloverRealPrice());    //设置映射真实价格

                AddDataFlag(Enum_Data_AutoSwapPosition());    //设置自动换仓

                AddDataFlag(Enum_Data_IgnoreSwapSignalCalc());    //设置忽略换仓信号计算
                
                SetOrderMap2MainSymbol();    //设置委托映射到主力
            }
        }
    }
    
    //Bar更新事件函数,参数indexs表示变化的数据源图层ID数组
    OnBar(ArrayRef<Integer> indexs)
    {    
        data0.lots_num = CalcuTradeLots();
        //计算多空线
        // 短周期
        data0.dkx_a = (3*data0.Close[0]+data0.Low[0]+data0.Open[0]+data0.High[0])/6;//3倍收盘价与最高价、最低价、开盘价之和的均值。
        data0.dkx_b = data0.WAverage(data0.dkx_a, 2*dkx_k1);
        data0.dkx_d = data0.Average(data0.dkx_b, dkx_k1);//对B值做10周期平均计算。
        data0.cross_over = data0.CrossOver(data0.dkx_b, data0.dkx_d);
        data0.cross_under = data0.CrossUnder(data0.dkx_b, data0.dkx_d);
        data0.is_over = data0.dkx_b > data0.dkx_d;
        data0.is_under = data0.dkx_b < data0.dkx_d;
        
        // 中周期
        data1.dkx_a = (3*data1.Close[0]+data1.Low[0]+data1.Open[0]+data1.High[0])/6;//3倍收盘价与最高价、最低价、开盘价之和的均值。
        data1.dkx_b = data1.WAverage(data1.dkx_a, 2*dkx_k2);
        data1.dkx_d = data1.Average(data1.dkx_b, dkx_k2);//对B值做10周期平均计算。
        data1.cross_over = data1.CrossOver(data1.dkx_b, data1.dkx_d);
        data1.cross_under = data1.CrossUnder(data1.dkx_b, data1.dkx_d);
        data1.is_over = data1.dkx_b > data1.dkx_d;
        data1.is_under = data1.dkx_b < data1.dkx_d;
        
        //短周期开仓
        if (data0.MarketPosition <= 0)
        {
            if (data0.is_over and data1.is_over and cur_lot == 0)
            {
                print("##### time : " + Text(Time));
                print("marketPosition : " + Text(data0.MarketPosition));
                print("cur_lot : " + Text(cur_lot));
                data0.Buy(data0.lots_num, data0.Close);
                cur_lot = 1;
                Print("buy");
                print("marketPosition : " + Text(data0.MarketPosition));
                print("cur_lot : " + Text(cur_lot));
            }
        }
        if (data0.MarketPosition >= 0)
        {
            if (data0.is_under and data1.is_under and cur_lot == 0)
            {
                print("##### time : " + Text(Time));
                print("marketPosition : " + Text(data0.MarketPosition));
                print("cur_lot : " + Text(cur_lot));
                data0.SellShort(data0.lots_num, data0.Close);
                cur_lot = 1;
                Print("SellShort");
                print("marketPosition : " + Text(data0.MarketPosition));
                print("cur_lot : " + Text(cur_lot));
            }
        }
        
        //平仓
        if (data0.MarketPosition > 0)
        {
            //技术 止损 止盈
            if (data0.cross_under)
            {
                Commentary("cross_under 0");
                Commentary("Sell 0");
                data0.Sell(0, data0.Close);
            }
        }
        else if(data0.MarketPosition < 0)
        {
            //技术 止损 止盈
            if (data0.cross_over)
            {
                Commentary("cross_over 0");
                Commentary("BuyToCover 0");
                data0.BuyToCover(0, data0.Close);
            }
        }
        
        //画图
        data0.PlotNumeric("b0", data0.dkx_b);
        data0.PlotNumeric("d0", data0.dkx_d);
        data0.PlotNumeric("b1", data1.dkx_b);
        data0.PlotNumeric("d1", data1.dkx_d);
        data1.PlotNumeric("b1", data1.dkx_b);
        data1.PlotNumeric("d1", data1.dkx_d);
    }
    
    //下一个Bar开始前,重新执行当前bar最后一次,参数为当前bar的图层数组
    OnBarClose(ArrayRef<Integer> indexs)
    {
        cur_lot = 0;
    }
 

请问为什么这个会频繁开仓,我是通过cur_lot来控制每条K线只开一次仓,为了防止信号闪烁。我看到确实开仓成功了,然后下一条K线的时候还继续开仓,那是为什么呢,我已经是有marketPosition判断了。

tblaocai

您好!看了一遍公式,您的问题是对公式运行机制没了解清楚。BuySell指令要求在一根BAR中的信号产生后不能消失,信号产生后每个Tick运行都要保持信号的存在,这种同一BAR的多个Tick运行产生的信号并不会像你想象的导致重复发单。反倒是您想用全局变量来控制下个Tick不产生信号,会导致信号消失。所以,就会开仓成功后,信号消失了。下根BAR又继续开仓。另外您的公式中,用Close来做判断是会产生信号消失的,不能这么用

2022-01-10 15:30
suyesheng
@tblaocai

请问用全局变量来控制下个Tick不产生信号,为什么会导致信号消失?

2022-01-10 20:29
kyover
@suyesheng

信号消失的意思就是同一根bar上,前面的tick使信号满足,后面的tick使信号不满足,导致前面出现信号,后面不出现信号,直观上就像信号消失了一样。

2022-01-11 16:26
suyesheng

用全局变量来控制下个Tick不产生信号,为什么会导致信号消失?

2022-01-10 20:28
tblaocai
@suyesheng

我说下正常的公式机制,以单数据源为例,历史K线公式运行一次,实时K线每个tick运行一次,如果某个Tick满足交易条件,发出交易信号,系统会同时发送委托。正常情况下,只要发出交易信号了,后续的Tick也要能继续满足交易条件了,这样信号就可以保持到这根K线结束。这样将来这根BAR成为历史K线了,根据交易条件也是满足交易条件的,这个信号就不会出现闪烁。测试结果和实际交易结果就是一样的。这是正确编写的公式的运行和回测的状态。

然后说下有问题的策略写法。某个Tick满足交易条件,发出交易信号,系统会同时发送委托。但是后续Tick有可能不满足交易条件了,导致信号没有了,但系统发出的单子是铁定已经成交了的。这种情况就叫信号消失。因为一般不满足交易条件,都是因为交易后不利导致的,所以这样写策略导致的结果就是,只要交易不利,就会把产生过的信号抹掉,只有有利的交易才会留下,这样测试结果会非常好。但实际交易能抹掉吗?肯定不能,所以这种策略也叫使用未来数据,是我们尽量要规避的。

现在您的策略是怎么写的呢?成交了,我就用全局变量让它下个Tick不产生信号。这不是故意往我们要规避的错误的方向去吗?所以,我说您没有搞清楚公式机制。

2022-01-10 22:53
suyesheng
@tblaocai

谢谢,我思考一下。

2022-01-11 04:18
suyesheng
@tblaocai

//------------------------------------------------------------------------
// 简称: DKXTrade
// 名称: 多空线交易策略
// 类别: 公式应用
// 类型: 用户应用
// 输出: Void
// 策略说明:多空线趋势策略
// 系统要素:
//    1. 短周期多空线
//    2. 中周期多空线
//    3. 长周期多空线
// 入场条件:
//    短周期与长周期同方向
//    短周期金叉或死叉的时候
//    长周期金叉或死叉的时候        
//    DKXCD 超过阈值 并且在0轴上方下方
// 出场条件:
//    短周期金叉或死叉的时候    
//
//------------------------------------------------------------------------
Params
    Numeric dkx_k1(10);                    // 多空线
    Numeric dkx_k2(10);                    // 多空线
    Numeric dkxcd_length(9);            // 平滑异步多空线
    Numeric dkxcd_threshold(2.5);        // 平滑异步多空线阈值
    Enum<String> lots_mode(["资金占比","持仓市值","固定手数"]);     // 开仓手数计算类型
    Integer fixed_lots(1);                // 固定手数
    Numeric fixed_money(100000);        // 固定市值
    Numeric money_rate(0.1);            // 资金比例,0.1=10%
    bool is_rollover(True);                // 是否还原复权前价格
    bool is_cut(False);                    // 是否强制止损
    
Vars
    //此处添加变量
    Series<Numeric> dkx_a;
    Series<Numeric> dkx_b;
    Series<Numeric> dkx_d;
    bool is_over;
    bool is_under;
    bool cross_over;
    bool cross_under;
    Series<Numeric> dkxcd_diff; 
    Numeric dkxcd_avg;
    Numeric dkxcd_value;
    Integer lots_num;
    Global Integer cur_pos(0);        //当前k线的单子方向
    Global Integer cur_lot(0);        //当前k线的单子手数
    Global Integer cur_price(0);    //当前k线的单子价格
Defs
    Integer CalcuTradeLots()        // 交易手数计算函数
    {
        Integer myLots;
        if(lots_mode=="资金占比")
        {
            myLots = Max(1,IntPart((Portfolio_CurrentEquity*money_rate/MarginRatio)/(Open*contractunit*bigpointvalue)));
        }
        else if(lots_mode=="持仓市值")
        {
            myLots = Max(1,IntPart(fixed_money/(Open*contractunit*bigpointvalue)));
        }
        else if(lots_mode=="固定手数")
            myLots = fixed_lots;
        else 
            myLots = fixed_lots;
        return myLots;
    }
    
Events
    OnInit()
    {
        Range[0:DataCount-1]
        {
            if (is_rollover)
            {
                AddDataFlag(Enum_Data_RolloverBackWard());    //设置后复权

                AddDataFlag(Enum_Data_RolloverRealPrice());    //设置映射真实价格

                AddDataFlag(Enum_Data_AutoSwapPosition());    //设置自动换仓

                AddDataFlag(Enum_Data_IgnoreSwapSignalCalc());    //设置忽略换仓信号计算
                
                SetOrderMap2MainSymbol();    //设置委托映射到主力
            }
        }
    }
    
    //Bar更新事件函数,参数indexs表示变化的数据源图层ID数组
    OnBar(ArrayRef<Integer> indexs)
    {    
        data0.lots_num = CalcuTradeLots();
        //计算多空线
        // 短周期
        data0.dkx_a = (3*data0.Close[0]+data0.Low[0]+data0.Open[0]+data0.High[0])/6;//3倍收盘价与最高价、最低价、开盘价之和的均值。
        data0.dkx_b = data0.WAverage(data0.dkx_a, 2*dkx_k1);
        data0.dkx_d = data0.Average(data0.dkx_b, dkx_k1);//对B值做10周期平均计算。
        data0.cross_over = data0.CrossOver(data0.dkx_b, data0.dkx_d);
        data0.cross_under = data0.CrossUnder(data0.dkx_b, data0.dkx_d);
        data0.is_over = data0.dkx_b > data0.dkx_d;
        data0.is_under = data0.dkx_b < data0.dkx_d;
        
        // 中周期
        data1.dkx_a = (3*data1.Close[0]+data1.Low[0]+data1.Open[0]+data1.High[0])/6;//3倍收盘价与最高价、最低价、开盘价之和的均值。
        data1.dkx_b = data1.WAverage(data1.dkx_a, 2*dkx_k2);
        data1.dkx_d = data1.Average(data1.dkx_b, dkx_k2);//对B值做10周期平均计算。
        data1.cross_over = data1.CrossOver(data1.dkx_b, data1.dkx_d);
        data1.cross_under = data1.CrossUnder(data1.dkx_b, data1.dkx_d);
        data1.is_over = data1.dkx_b > data1.dkx_d;
        data1.is_under = data1.dkx_b < data1.dkx_d;
        
        //短周期开仓
        if (cur_pos == 0)
        {
            if (data0.MarketPosition <= 0)
            {
                if (data0.is_over and data1.is_over and cur_pos == 0)
                {
                    data0.Buy(data0.lots_num, data0.Close);
                    cur_pos = 1;
                    cur_lot = data0.lots_num;
                    cur_price = data0.Close;
                }
            }
            if (data0.MarketPosition >= 0)
            {
                if (data0.is_under and data1.is_under and cur_pos == 0)
                {
                    data0.SellShort(data0.lots_num, data0.Close);
                    cur_pos = -1;
                    cur_lot = data0.lots_num;
                    cur_price = data0.Close;
                }
            }
        }
        
        //平仓
        if (cur_pos == 0)
        {
            if (data0.MarketPosition > 0)
            {
                //技术 止损 止盈
                if (data0.cross_under)
                {
                    Commentary("cross_under 0");
                    Commentary("Sell 0");
                    data0.Sell(0, data0.Close);
                    cur_pos = 1;
                    cur_lot = 0;
                    cur_price = data0.Close;
                }
            }
            else if(data0.MarketPosition < 0)
            {
                //技术 止损 止盈
                if (data0.cross_over)
                {
                    Commentary("cross_over 0");
                    Commentary("BuyToCover 0");
                    data0.BuyToCover(0, data0.Close);
                    cur_pos = -1;
                    cur_lot = 0;
                    cur_price = data0.Close;
                }
            }
        }

        // 当前K线开仓平仓之后保持开仓信号
        if (cur_pos == 1)
        {
            if (cur_lot > 0)
                data0.Buy(cur_lot, cur_price);
            else
                data0.Sell(0, cur_price);
        }
        else if (cur_pos == -1)
        {
            if (cur_lot > 0)
                data0.SellShort(cur_lot, cur_price);
            else
                data0.BuyToCover(0, cur_price);
        }            
        
        //画图
        data0.PlotNumeric("b0", data0.dkx_b);
        data0.PlotNumeric("d0", data0.dkx_d);
        data0.PlotNumeric("b1", data1.dkx_b);
        data0.PlotNumeric("d1", data1.dkx_d);
        data1.PlotNumeric("b1", data1.dkx_b);
        data1.PlotNumeric("d1", data1.dkx_d);
    }
    
    //下一个Bar开始前,重新执行当前bar最后一次,参数为当前bar的图层数组
    OnBarClose(ArrayRef<Integer> indexs)
    {
        // 当k线结束后清理当前k线的信号
        cur_pos = 0;
        cur_lot = 0;
        cur_price = 0;
    }

//------------------------------------------------------------------------
// 编译版本    2021/07/04 230331
// 版权所有    suyesheng
// 更改声明    TradeBlazer Software保留对TradeBlazer平台
//            每一版本的TradeBlazer公式修改和重写的权利
//------------------------------------------------------------------------

你好,我对代码进行了修改,这样貌似就能在当前k线触发信号之后阻止信号的消失了吧

2022-01-11 12:40
tblaocai
@suyesheng

粗略看了下,您这大段代码中,关键的地方还是没有改——不能用全局变量来人为地让下一个Tick不满足交易条件。

2022-01-11 16:36
您未登录,请先 登录注册 后发表评论
顶部