咨询代码
Params Numeric AvgLength(5); // 均线周期 Numeric AvgDisplace(5); // 置换均线向后平移Bar数 Numeric ValidBars1(5); // 开仓先决条件之一(收盘价上穿DMA均线)条件值保持有效的BAR数 Numeric ValidBars2(5); // 开仓先决条件之二(上穿后再下穿)条件值保持有效的BAR数 Numeric ValidBars3(5); // 开仓先决条件(上穿再下穿再上穿)条件值保持有效的BAR数 Numeric TrailStopBars(5); // 多少根BAR的最低价作为跟踪止损价 Vars Series<Numeric> MA; // 均线 Series<Numeric> DMA; // 置换均线 Series<Bool> ConCrossOver; // 当前BAR是否上穿DMA Series<Bool> ConCrossUnder; // 当前BAR是否下穿DMA Numeric BarsLastCrsOvr; // 最近一次上穿离现在的BAR数 Numeric BarsFstCrsUnd; // 最近倒数第二次下穿离现在的BAR数 Numeric BarsSecCrsUnd; // 最近的一次下穿离现在的BAR数 Series<Bool> EntryFlag(False); // 开仓标志 Series<Numeric> EntryPoint; // 突破开仓的价格 Series<Numeric> EntryCount; // 满足开仓先决条件的BAR计数 Numeric ReversalPrice; // 趋势反向的平仓价格 Numeric TrailStopPrice; // 跟踪止损的平仓价格 Events OnBar(ArrayRef<Integer> indexs) { // 计算置换均线 MA = Average(Close, AvgLength); DMA = MA[AvgDisplace]; PlotNumeric("DMA",DMA); // 判断收盘价是否穿越置换均线 ConCrossOver = CrossOver(Close,DMA); ConCrossUnder = CrossUnder(Close,DMA); // 计算最近的一次上穿发生的BAR离当前BAR的根数 BarsLastCrsOvr = NthCon(ConCrossOver==True,1); // 计算最近的两次下穿发生的BAR离当前BAR的根数 BarsFstCrsUnd = NthCon(ConCrossUnder==True,2); BarsSecCrsUnd = NthCon(ConCrossUnder==True,1); // 设置开仓标志 If(ConCrossUnder And BarsLastCrsOvr - BarsSecCrsUnd <= ValidBars2 And BarsFstCrsUnd - BarsLastCrsOvr <= ValidBars1) { EntryFlag = True; EntryPoint = Low - MinMove * PriceScale; EntryCount = 0; } Commentary("EntryFlag = "+iifstring(EntryFlag,"True","False")); Commentary("EntryPoint = "+Text(EntryPoint)); Commentary("EntryCount = "+Text(EntryCount)); // 开仓 If(MarketPosition == 0 And EntryCount <= ValidBars3) { If(EntryFlag And Low <= EntryPoint And Vol > 0) { SellShort(0, Min(Open,EntryPoint)); } Else { EntryCount = EntryCount + 1; } } // 开仓或者开仓先决条件已过有效BAR数,修改开仓标志 If(MarketPosition == -1 Or EntryCount > ValidBars3) { EntryFlag = False; } // 止损价格计算 ReversalPrice = DMA[1] + MinMove * PriceScale; TrailStopPrice = Highest(High[1],TrailStopBars); Commentary("ReversalPrice = "+Text(ReversalPrice)); Commentary("TrailStopPrice = "+Text(TrailStopPrice)); // 平仓 If(MarketPosition == -1 And BarsSinceEntry > 0 And Vol > 0) { If(High >= Min(ReversalPrice,TrailStopPrice)) { BuyToCover(0,Max(Open, Min(ReversalPrice,TrailStopPrice) ) ); } } }老师你好,我研究开拓者自带的 基于置换均线的二次穿越突破系统空 这个策略的时候,发现这段代码没有回溯,If(ConCrossUnder And BarsLastCrsOvr - BarsSecCrsUnd <= ValidBars2 And BarsFstCrsUnd - BarsLastCrsOvr <= ValidBars1) { EntryFlag = True; EntryPoint = Low - MinMove * PriceScale; EntryCount = 0; }而且EntryFlag作为开仓条件之一,他也没回溯,这样不会导致信号闪烁吗? 这是开拓者自带的策略,不可能会闪烁才对,这是什么原理呢?老师指导一下,谢谢// 开仓 If(MarketPosition == 0 And EntryCount <= ValidBars3) { If(EntryFlag And Low <= EntryPoint And Vol > 0) { SellShort(0, Min(Open,EntryPoint)); } Else { EntryCount = EntryCount + 1; } }
您好,这个内置策略是我当年写的,我有点忘了当时为啥没有加上回溯,看上去确是有信号闪烁的可能,我上午检查并测试一下再回复您吧。感谢您指出我们代码中的问题!
回复:我中午测试了一下,确实有信号闪烁的情况。我重新回忆了一下策略的逻辑,在修复信号闪烁问题的同时,我发现策略实现逻辑上还有问题,因为几次穿越的计算每根BAR都在计算,新的计算结果又会覆盖上次的进场机会。这里就有个选择,当前BAR是继续按上根BAR的进场机会判断,还是按新的计算结果判断。我现在改了一个版本是优先按上根BAR的进场机会。我只写了做空的部分,先发出来供您参考下。内置代码的修改,我会再多测试测试,再提交给研发更新。
回复://------------------------------------------------------------------------// 简称: test_doubleyourfun_S// 名称: 临时测试, 基于置换均线的二次穿越突破系统空// 类别: 策略应用// 类型: 用户应用// 输出: Void//------------------------------------------------------------------------//----------------------------------------------------------------------//// 策略说明:// 本策略是基于置换均线的二次穿越突破系统// // 系统要素:// 1. 将移动平均K线向后平移一定BAR数即为置换均线// 2. 相隔一定BAR数的收盘价二次穿越置换均线// 3. 二次穿越完成时那根BAR的高点(或低点)作为突破进场价// 4. 完成二次穿越的一定BAR数内突破// 入场条件:// 1. 有效期内价格向上突破设定进场价做多// 2. 有效期内价格向下突破设定进场价做空// 出场条件: // 1. 价格反向穿越均线后止损// 2. 基于N根K线的高低点的跟踪止损//// 注: 当前策略仅为做空系统, 如需做多, 请参见CL_DoubleYourFun_L//----------------------------------------------------------------------//Params Numeric AvgLength(5); // 均线周期 Numeric AvgDisplace(5); // 置换均线向后平移Bar数 Numeric ValidBars1(5); // 开仓先决条件之一(收盘价上穿DMA均线)条件值保持有效的BAR数 Numeric ValidBars2(5); // 开仓先决条件之二(上穿后再下穿)条件值保持有效的BAR数 Numeric ValidBars3(5); // 开仓先决条件(上穿再下穿再上穿)条件值保持有效的BAR数 Numeric TrailStopBars(5); // 多少根BAR的最低价作为跟踪止损价 Vars Series<Numeric> MAVal; // 均线 Series<Numeric> DMA; // 置换均线 Series<Bool> ConCrossOver; // 当前BAR是否上穿DMA Series<Bool> ConCrossUnder; // 当前BAR是否下穿DMA Numeric BarsLastCrsOvr; // 最近一次上穿离现在的BAR数 Numeric BarsFstCrsUnd; // 最近倒数第二次下穿离现在的BAR数 Numeric BarsSecCrsUnd; // 最近的一次下穿离现在的BAR数 Series<Bool> EntryFlag(False); // 开仓标志 Series<Numeric> EntryPoint; // 突破开仓的价格 Series<Numeric> EntryCount; // 满足开仓先决条件的BAR计数 Numeric ReversalPrice; // 趋势反向的平仓价格 Numeric TrailStopPrice; // 跟踪止损的平仓价格 Events OnReady() { Range[0:DataSourceSize() - 1] { setPlotOption("DMA", "begin-bar", AvgLength); } } OnBar(ArrayRef<Integer> indexs) { // 计算置换均线 MAVal = Average(Close, AvgLength); DMA = MAVal[AvgDisplace]; PlotNumeric("DMA",DMA); // 开仓 If(MarketPosition == 0 And EntryCount <= ValidBars3) { If(EntryFlag[1]) { If(Low <= EntryPoint And Vol > 0) { SellShort(0, Min(Open, EntryPoint)); } Else { EntryCount = EntryCount + 1; } } } // 开仓或者开仓先决条件已过有效BAR数,修改开仓标志 If(MarketPosition == -1 Or EntryCount > ValidBars3) { EntryFlag = False; } // 止损价格计算 ReversalPrice = DMA[1] + MinMove * PriceScale; TrailStopPrice = Highest(High[1],TrailStopBars); Commentary("ReversalPrice = "+Text(ReversalPrice)); Commentary("TrailStopPrice = "+Text(TrailStopPrice)); // 平仓 If(MarketPosition == -1 And BarsSinceEntry > 0 And Vol > 0) { If(High >= Min(ReversalPrice,TrailStopPrice)) { BuyToCover(0,Max(Open, Min(ReversalPrice,TrailStopPrice) ) ); } } // 判断收盘价是否穿越置换均线 ConCrossOver = CrossOver(Close,DMA); Commentary("均线上穿=" + iifstring(ConCrossOver,"是","否")); ConCrossUnder = CrossUnder(Close,DMA); Commentary("均线下穿=" + iifstring(ConCrossUnder,"是","否")); // 计算最近的一次上穿发生的BAR离当前BAR的根数 BarsLastCrsOvr = NthCon(ConCrossOver==True,1); Commentary("最近上穿Offset=" + Text(BarsLastCrsOvr)); // 计算最近的两次下穿发生的BAR离当前BAR的根数 BarsFstCrsUnd = NthCon(ConCrossUnder==True,2); BarsSecCrsUnd = NthCon(ConCrossUnder==True,1); Commentary("前2次下穿,首次Offset=" + Text(BarsFstCrsUnd)); Commentary("前2次下穿,第2次Offset=" + Text(BarsSecCrsUnd)); // 设置开仓标志 If(BarsLastCrsOvr > 0 And BarsLastCrsOvr - BarsSecCrsUnd <= ValidBars2 And BarsFstCrsUnd - BarsLastCrsOvr <= ValidBars1) { EntryFlag = True; EntryPoint = Low - MinMove * PriceScale; EntryCount = 0; } Commentary("EntryFlag = "+iifstring(EntryFlag,"True","False")); Commentary("EntryPoint = "+Text(EntryPoint)); Commentary("EntryCount = "+Text(EntryCount)); } //------------------------------------------------------------------------// 编译版本 GS2014.10.25// 版权所有 TradeBlazer Software 2003-2045// 更改声明 TradeBlazer Software保留对TradeBlazer平// 台每一版本的TradeBlazer公式修改和重写的权利//------------------------------------------------------------------------//------------------------------------------------------------------------// 编译版本 2026/1/16 63940// 版权所有 tblaocai// 更改声明 TradeBlazer Software保留对TradeBlazer平台// 每一版本的TradeBlazer策略修改和重写的权利//------------------------------------------------------------------------
回复:😀感谢老师