关于跨周期控制变量失效的问题

老师们好,最近在跨周期程序调试上,我都要吐了,按照教学视频我改写了海龟交易策略,但是控制变量总是在大周期的onbar结束后丢失,导致程序无法进行后续的交易控制,也都是按照视频教学在大周期上进行运算,小周期上交易,但是控制变量sendorderthisbar就算是发生了交易,在onbar的当根k线还是true,但是onbar结束之后就变成false了,就算是在当根k线的onbarclose打印出来都是false....仔细检查了程序,没有发现其他赋值false的语句,不知道是怎么回事,请老师帮忙分析一下,感谢拉!代码如下:Params Array<String> Mysymbol([\"sc2408.INE\"]); //品种参数 Numeric TN(1); //周期数 Enum<String> TT1([\"d\",\"h\",\"m\"]); //周期1单位 Enum<String> TT2([\"d\",\"h\",\"m\"]); //周期2单位 Numeric nEntries(3); // 最大建仓次数 Numeric RiskRatio(1); // % Risk Per N ( 0 - 100) Numeric ATRLength(20); // 平均波动周期 ATR Length Numeric boLength(20); // 短周期 BreakOut Length Numeric fsLength(55); // 长周期 FailSafe Length Numeric teLength(10); // 离市周期 Trailing Exit Length Bool LastProfitableTradeFilter(True); // 使用入市过滤条件Vars Numeric i; Numeric MinPoint; // 最小变动单位 Series<Numeric> AvgTR; // ATR Numeric N; // N 值 Numeric TotalEquity; // 按最新收盘价计算出的总资产 Numeric TurtleUnits; // 交易单位 Series<Numeric> DonchianHi; // 唐奇安通道上轨,延后1个Bar Series<Numeric> DonchianLo; // 唐奇安通道下轨,延后1个Bar Series<Numeric> fsDonchianHi; // 唐奇安通道上轨,延后1个Bar,长周期 Series<Numeric> fsDonchianLo; // 唐奇安通道下轨,延后1个Bar,长周期 Numeric ExitHighestPrice; // 离市时判断需要的N周期最高价 Numeric ExitLowestPrice; // 离市时判断需要的N周期最低价 Numeric myEntryPrice; // 开仓价格 Numeric myExitPrice; // 平仓价格 Bool SendOrderThisBar; // 当前Bar有过交易 Series<Numeric> preEntryPrice(0); // 前一次开仓的价格 Series<Bool> PreBreakoutFailure(false); // 前一次突破是否失败Events OnInit() { //SetBasePeriod(\"1m\"); For i=0 to GetArraySize(Mysymbol)-1 { //SubscribeBar(Mysymbol[i],Text(TN)+TT1); SubscribeBar(Mysymbol[i],\"1h\",20240601); SubscribeBar(Mysymbol[i],\"1m\",20240601); } } OnBarOpen(ArrayRef<Integer> indexs) { //If(GetArraySize(indexs) == 0) Return; } OnBar(ArrayRef<Integer> indexs) { print(\"++++++++++++++++++++++++++\"); Numeric i; Numeric resultN = 1; //如果大周期图层还在运行,小周期运行结束,则传输控制信号 /* if (data0.BarExistStatus == 1 && data1.BarExistStatus <> 1) { data0.SendOrderThisBar = data1.SendOrderThisBar; data0.PreBreakoutFailure = data1.PreBreakoutFailure; }*/ For i=0 to DataSourceSize -1 { //SubscribeBar(Mysymbol[i],Text(TN)+TT1); resultN = resultN * data[i].BarExistStatus; } If(resultN <> 1) return; If(BarStatus == 0) { data0.preEntryPrice = InvalidNumeric; data0.PreBreakoutFailure = false; } MinPoint = MinMove*PriceScale; AvgTR = XAverage(TrueRange,ATRLength); N = AvgTR[1]; TotalEquity = Portfolio_CurrentCapital() + Portfolio_UsedMargin(); TurtleUnits = (TotalEquity*RiskRatio/100) /(N * ContractUnit()*BigPointValue()); TurtleUnits = IntPart(TurtleUnits); // 对小数取整 data0.DonchianHi = HighestFC(data0.High[1],boLength); data0.DonchianLo = LowestFC(data0.Low[1],boLength); data0.fsDonchianHi = HighestFC(data0.High[1],fsLength); data0.fsDonchianLo = LowestFC(data0.Low[1],fsLength); data0.ExitLowestPrice = LowestFC(data0.Low[1],teLength); data0.ExitHighestPrice = HighestFC(data0.High[1],teLength); data0.PlotNumeric(\"DonchianHi\",data0.DonchianHi); data0.PlotNumeric(\"DonchianLo\",data0.DonchianLo); data0.PlotNumeric(\"fsDonchianHi\",data0.fsDonchianHi,0,yellow); data0.PlotNumeric(\"fsDonchianLo\",data0.fsDonchianLo,0,blue); data0.Commentary(\"N=\"+Text(data0.N)+\",barnum=\"+Text(data0.CurrentBar)); data0.Commentary(\"data0.preEntryPrice=\"+Text(data0.preEntryPrice)); data0.Commentary(\"PreBreakoutFailure=\"+IIFString(data0.PreBreakoutFailure,\"True\",\"False\")); data0.Commentary(\"SendOrderThisBar=\"+IIFString(data0.SendOrderThisBar,\"True\",\"False\")); //print(\"SendOrderThisBar=\"+IIFString(data0.SendOrderThisBar,\"True\",\"False\")); // 当不使用过滤条件,或者使用过滤条件并且条件为data0.PreBreakoutFailure为True进行后续操作 If(data0.MarketPosition == 0 && ((!LastProfitableTradeFilter) Or (data0.PreBreakoutFailure))) { print(\"111r=\"+IIFString(data0.SendOrderThisBar,\"True\",\"False\")); // 突破开仓 If(High > data0.DonchianHi && TurtleUnits >= 1 && data0.SendOrderThisBar==false) { print(\"222=\"+IIFString(data0.SendOrderThisBar,\"True\",\"False\")); // 开仓价格取突破上轨+一个价位和最高价之间的较小值,这样能更接近真实情况,并能尽量保证成交 data0.myEntryPrice = min(high,data0.DonchianHi + MinPoint); data0.myEntryPrice = IIF(myEntryPrice < Open, Open,data0.myEntryPrice); // 大跳空的时候用开盘价代替 data0.preEntryPrice = data0.myEntryPrice; data1.Buy(TurtleUnits,data0.myEntryPrice); data0.SendOrderThisBar = True; data0.PreBreakoutFailure = False; } If(Low < data0.DonchianLo && TurtleUnits >= 1 && data0.SendOrderThisBar==false) { print(\"333=\"+IIFString(data0.SendOrderThisBar,\"True\",\"False\")); // 开仓价格取突破下轨-一个价位和最低价之间的较大值,这样能更接近真实情况,并能尽量保证成交 data0.myEntryPrice = max(low,data0.DonchianLo - MinPoint); data0.myEntryPrice = IIF(myEntryPrice > Open, Open,data0.myEntryPrice); // 大跳空的时候用开盘价代替 data0.preEntryPrice = data0.myEntryPrice; data1.SellShort(TurtleUnits,data0.myEntryPrice); data0.SendOrderThisBar = True; data0.PreBreakoutFailure = False; } } // 长周期突破开仓 Failsafe Breakout point If(data0.MarketPosition == 0) { data0.Commentary(\"fsDonchianHi=\"+Text(fsDonchianHi)); If(High > data0.fsDonchianHi && TurtleUnits >= 1 && data0.SendOrderThisBar==false) { print(\"444=\"+IIFString(data0.SendOrderThisBar,\"True\",\"False\")); // 开仓价格取突破上轨+一个价位和最高价之间的较小值,这样能更接近真实情况,并能尽量保证成交 data0.myEntryPrice = min(high,data0.fsDonchianHi + MinPoint); data0.myEntryPrice = IIF(myEntryPrice < Open, Open,data0.myEntryPrice); // 大跳空的时候用开盘价代替 data0.preEntryPrice = data0.myEntryPrice; data1.Buy(TurtleUnits,data0.myEntryPrice); data0.SendOrderThisBar = True; data0.PreBreakoutFailure = False; } data0.Commentary(\"fsDonchianLo=\"+Text(fsDonchianLo)); If(Low < data0.fsDonchianLo && TurtleUnits >= 1 && data0.SendOrderThisBar==false) { print(\"5555=\"+IIFString(data0.SendOrderThisBar,\"True\",\"False\")); // 开仓价格取突破下轨-一个价位和最低价之间的较大值,这样能更接近真实情况,并能尽量保证成交 data0.myEntryPrice = max(low,data0.fsDonchianLo - MinPoint); data0.myEntryPrice = IIF(myEntryPrice > Open, Open,data0.myEntryPrice); // 大跳空的时候用开盘价代替 data0.preEntryPrice = data0.myEntryPrice; data1.SellShort(TurtleUnits,data0.myEntryPrice); data0.SendOrderThisBar = True; data0.PreBreakoutFailure = False; data0.Commentary(\"SendOrderThisBar=\"+IIFString(data0.SendOrderThisBar,\"True\",\"False\")); } } data0.Commentary(\"22SendOrderThisBar=\"+IIFString(data0.SendOrderThisBar,\"True\",\"False\")); If(data0.MarketPosition == 1) // 有多仓的情况 { data0.Commentary(\"ExitLowestPrice=\"+Text(ExitLowestPrice)); If(Low < data0.ExitLowestPrice && data0.SendOrderThisBar==false) { data0.myExitPrice = max(Low,data0.ExitLowestPrice - MinPoint); data0.myExitPrice = IIF(myExitPrice > Open, Open,data0.myExitPrice); // 大跳空的时候用开盘价代替 data1.Sell(0,data0.myExitPrice); // 数量用0的情况下将全部平仓 }Else { If(data0.preEntryPrice!=InvalidNumeric && TurtleUnits >= 1) { If(Open >= data0.preEntryPrice + 0.5*data0.N && CurrentEntries < nEntries && data0.SendOrderThisBar==false) // 如果开盘就超过设定的1/2N,则直接用开盘价增仓。 { data0.myEntryPrice = Open; data0.preEntryPrice = data0.myEntryPrice; data1.Buy(TurtleUnits,data0.myEntryPrice); data0.SendOrderThisBar = True; } while(High >= data0.preEntryPrice + 0.5*data0.N && CurrentEntries < nEntries && data0.SendOrderThisBar==false) // 以最高价为标准,判断能进行几次增仓 { data0.myEntryPrice = data0.preEntryPrice + 0.5 * data0.N; data0.preEntryPrice = data0.myEntryPrice; if(False == data1.Buy(TurtleUnits,data0.myEntryPrice)) { break; } data0.SendOrderThisBar = True; } } // 止损指令 If(Low <= data0.preEntryPrice - 2 * data0.N && data0.SendOrderThisBar == false) // 加仓Bar不止损 { data0.myExitPrice = data0.preEntryPrice - 2 * data0.N; data0.myExitPrice = IIF(myExitPrice > Open, Open,data0.myExitPrice); // 大跳空的时候用开盘价代替 data1.Sell(0,data0.myExitPrice); // 数量用0的情况下将全部平仓 data0.PreBreakoutFailure = True; } } }Else If(data0.MarketPosition ==-1) // 有空仓的情况 { // 求出持空仓时离市的条件比较值 data0.Commentary(\"ExitHighestPrice=\"+Text(data0.ExitHighestPrice)); If(High > data0.ExitHighestPrice && data0.SendOrderThisBar==false) { data0.myExitPrice = Min(High,data0.ExitHighestPrice + MinPoint); data0.myExitPrice = IIF(myExitPrice < Open, Open,data0.myExitPrice); // 大跳空的时候用开盘价代替 data1.BuyToCover(0,data0.myExitPrice); // 数量用0的情况下将全部平仓 }Else { If(data0.preEntryPrice!=InvalidNumeric && TurtleUnits >= 1) { If(Open <= data0.preEntryPrice - 0.5*data0.N && CurrentEntries < nEntries && data0.SendOrderThisBar==false) // 如果开盘就超过设定的1/2N,则直接用开盘价增仓。 { data0.myEntryPrice = Open; data0.preEntryPrice = data0.myEntryPrice; data1.SellShort(TurtleUnits,data0.myEntryPrice); data0.SendOrderThisBar = True; } while(Low <= data0.preEntryPrice - 0.5*data0.N && CurrentEntries < nEntries && data0.SendOrderThisBar==false) // 以最低价为标准,判断能进行几次增仓 { data0.myEntryPrice = data0.preEntryPrice - 0.5 * data0.N; data0.preEntryPrice = data0.myEntryPrice; if(False == data1.SellShort(TurtleUnits,data0.myEntryPrice)) { break; } data0.SendOrderThisBar = True; } } // 止损指令 If(High >= data0.preEntryPrice + 2 * data0.N && data0.SendOrderThisBar==false) // 加仓Bar不止损 { data0.myExitPrice = data0.preEntryPrice + 2 * data0.N; data0.myExitPrice = IIF(myExitPrice < Open, Open,data0.myExitPrice); // 大跳空的时候用开盘价代替 data1.BuyToCover(0,data0.myExitPrice); // 数量用0的情况下将全部平仓 data0.PreBreakoutFailure = True; } } } data0.Commentary(\"CurrentEntries = \" + Text(CurrentEntries)); } OnBarClose(ArrayRef<Integer> indexs) { /* print(\"111r=\"+IIFString(data0.SendOrderThisBar,\"True\",\"False\")); data0.SendOrderThisBar = data1.SendOrderThisBar; data0.PreBreakoutFailure = data1.PreBreakoutFailure; print(\"222r=\"+IIFString(data1.SendOrderThisBar,\"True\",\"False\")); */ /*if (data0.BarExistStatus == 1) { data0.SendOrderThisBar = False; data0.PreBreakoutFailure = False; if(data1.BarExistStatus == 1) { data1.SendOrderThisBar = False; data1.PreBreakoutFailure = False; } }*/ }

刚开始最好用最简单的模型去学习、测试海龟对初学者来说已经过于复杂多图层+各种逻辑控制涉及面太多了还有交易信号的闪烁都能搞到你精神崩塌

上个帖子已经回你了如果没有理解错的话大周期的bar内只交易一次小周期用来交易在onbaropen中 是大周期触发的话 把全局变量赋值为False有买卖就重置为True如果一个全局不够那就几个配合

局部类型的容器内容在本次驱动结束后就会清空,你为什么要用局部类型来作为状态变量?

回复:全局变量不能用图层标识。。。所以用了局部变量。用了全局变量会有一个问题,在小周期图层上,会多次修改全局控制变量,也一样的失去了控制的意义。

回复:natural类型是多图层全局变量建议零基础课程里再好好学学.... https://www.bilibili.com/video/BV1ZG411f7bt/?spm_id_from=333.999.0.0&vd_source=148cb1d807933f47bb50c46ed69d3c82

sendorderthisbar是局部类型?局部类型怎么做状态变量?