//------------------------------------------------------------------------
// 简称: MultiBOLLChannel_CloseEntry
// 名称: 多品种BOLL通道交易系统(收盘价开仓版)
// 类别: 策略应用
// 类型: 内建应用
//------------------------------------------------------------------------
Params
Numeric MALength(20); // MA周期
Numeric StdDevLength(20); // 标准差周期
Numeric StdDevMultiplier(2); // 标准差倍数
Numeric MaxOpenSymbols(1); // 最大开仓品种数量
Vars
Series<Numeric> MAValue; // MA值
Series<Numeric> StdDevValue; // 标准差
Series<Numeric> UpperBand; // 上轨
Series<Numeric> LowerBand; // 下轨
Natural CodeProperty codePro; // 合约属性
Global Numeric symbolCount; // 当前持有仓位的品种数量
Global Numeric w; // 用来调试 显示 OnBar中显示Range执行顺序
Global Numeric q; // 用来调试 显示 OnReady中显示Range执行顺序
Events
OnReady()
{
w=0;
q=0;
symbolCount = 0; // 初始化持仓品种数
Range[0:DataSourceSize()-1]
{
q=q+1;
Print("nReady "+ Text(q));
// 为每个图层设置回测参数
SetBackBarMaxCount(1 + Max(MALength, StdDevLength));
setPlotOption("MA", "begin-bar", MALength);
setPlotOption("Upper", "begin-bar", MALength);
setPlotOption("Lower", "begin-bar", MALength);
// 获取合约属性
GetProperty(codePro);
Print("symbol=" + codePro.symbol);
}
}
OnBar(ArrayRef<Integer> indexs)
{
Numeric i;
Range[i=0:DataSourceSize()-1]
{
GetProperty(codePro); // 当前品种属性
// 计算每个图层的指标
MAValue = AverageFC(Close, MALength);
StdDevValue = StandardDev(Close, StdDevLength, 2); // 使用StandardDev函数
UpperBand = MAValue + StdDevMultiplier * StdDevValue;
LowerBand = MAValue - StdDevMultiplier * StdDevValue;
// 主图显示BOLL通道
PlotNumeric("MA", MAValue);
PlotNumeric("Upper", UpperBand);
PlotNumeric("Lower", LowerBand);
// Commentary内容调整
String positionInfo = "当前持仓手数=" + Text(CurrentContracts()) + "\n当前持仓品种数=" + Text(symbolCount)+"\n方向="+Text(MarketPosition());
Commentary("当前图层索引=" + Text(i) +
"\n合约=" + codePro.symbol +
"\n当前持仓品种数=" + Text(symbolCount) +
"\n" + positionInfo);
// 交易逻辑(当前K线收盘满足条件,直接以收盘价交易)
Print("开仓之前=" + Text(Date) + ",方向="+Text(MarketPosition())+", 合约=" + codePro.symbol + ", 当前持仓品种数=" + Text(symbolCount) +"最大持仓数=" + Text(MaxOpenSymbols));
Bool tradeReturn = false;
// 开多条件:K线收盘上穿上轨,且未超过最大持仓品种数
If(MarketPosition() <> 1 && Close > UpperBand && symbolCount < MaxOpenSymbols)
{
Print("开多之前时间=" + Text(Date) + ",方向="+Text(MarketPosition())+", 合约=" + codePro.symbol + ", 当前持仓品种数=" + Text(symbolCount) +"最大持仓数=" + Text(MaxOpenSymbols));
tradeReturn=Buy(1,Close); // 固定开1手
if(tradeReturn)
{
if(MarketPosition() <> 0)
{
symbolCount = symbolCount + 1;
}
Print("[开多] 时间=" + Text(Date) + ",方向=" + Text(MarketPosition()) + ", 合约=" + codePro.symbol + ", 当前持仓品种数=" + Text(symbolCount) + "最大持仓数=" + Text(MaxOpenSymbols));
}
Else
{
Print("[开多] 失败 时间=" + Text(Date) + ",方向="+Text(MarketPosition())+", 合约=" + codePro.symbol + ", 当前持仓品种数=" + Text(symbolCount) +"最大持仓数=" + Text(MaxOpenSymbols));
}
}
// 平多条件:K线收盘下穿MA20
If(MarketPosition() == 1 && Close < MAValue)
{
Print("平多之前时间=" + Text(Date) + ",方向="+Text(MarketPosition())+", 合约=" + codePro.symbol + ", 当前持仓品种数=" + Text(symbolCount) +"最大持仓数=" + Text(MaxOpenSymbols));
tradeReturn=Sell(0,Close);
if(tradeReturn)
{
symbolCount=symbolCount-1;
Print("[平多] 时间=" + Text(Date) + ",方向="+Text(MarketPosition())+", 合约=" + codePro.symbol + ", 当前持仓品种数=" + Text(symbolCount) +"最大持仓数=" + Text(MaxOpenSymbols));
}
Else
{
Print("[平多] 失败 时间=" + Text(Date) + ",方向="+Text(MarketPosition())+", 合约=" + codePro.symbol + ", 当前持仓品种数=" + Text(symbolCount) +"最大持仓数=" + Text(MaxOpenSymbols));
}
}
// 开空条件:K线收盘下穿下轨,且未超过最大持仓品种数
If(MarketPosition() <> -1 && Close < LowerBand && symbolCount < MaxOpenSymbols)
{
Print("开空之前时间=" + Text(Date) + ",方向="+Text(MarketPosition())+", 合约=" + codePro.symbol + ", 当前持仓品种数=" + Text(symbolCount) +"最大持仓数=" + Text(MaxOpenSymbols));
tradeReturn=SellShort(1,Close); // 固定开1手
if(tradeReturn)
{
if(MarketPosition() <> 0)
{
symbolCount = symbolCount + 1;
}
Print("[开空] 时间=" + Text(Date) + ",方向="+Text(MarketPosition())+", 合约=" + codePro.symbol + ", 当前持仓品种数=" + Text(symbolCount) +"最大持仓数=" + Text(MaxOpenSymbols));
}
Else
{
Print("[开空] 失败 时间=" + Text(Date) + ",方向="+Text(MarketPosition())+", 合约=" + codePro.symbol + ", 当前持仓品种数=" + Text(symbolCount) +"最大持仓数=" + Text(MaxOpenSymbols));
}
}
// 平空条件:K线收盘上穿MA20
If(MarketPosition() == -1 && Close > MAValue)
{
Print("平空之前时间=" + Text(Date) + ",方向="+Text(MarketPosition())+", 合约=" + codePro.symbol + ", 当前持仓品种数=" + Text(symbolCount) +"最大持仓数=" + Text(MaxOpenSymbols));
tradeReturn=BuyToCover(0,Close);
if(tradeReturn)
{
symbolCount=symbolCount-1;
Print("[平空] 时间=" + Text(Date) + ",方向="+Text(MarketPosition())+", 合约=" + codePro.symbol + ", 当前持仓品种数=" + Text(symbolCount) +"最大持仓数=" + Text(MaxOpenSymbols));
}
Else
{
Print("[平空] 失败 时间=" + Text(Date) + ",方向="+Text(MarketPosition())+", 合约=" + codePro.symbol + ", 当前持仓品种数=" + Text(symbolCount) +"最大持仓数=" + Text(MaxOpenSymbols));
}
}
w=w+1;
}
}
//------------------------------------------------------------------------
// 编译版本 GS2010.12.08
// 版权所有 TradeBlazer Software 2003-2025
// 更改声明 TradeBlazer Software保留对TradeBlazer平
// 台每一版本的TradeBlazer公式修改和重写的权利
//------------------------------------------------------------------------
策略逻辑是 以BOLL通道 为基准 上穿上轨开多 下轨开空 中轨平仓。默认开仓1手
设置了一个最大开仓品种的限制默认为1,以全局变量Global Numeric symbolCount; 作为判断。
复现路径 先打开螺纹钢指数合约的K线,缩小到最早的时间,打开策略应用设置把所有指标勾选都去掉只显示K线, 然后添加沪铅 沪锡 沪锌 指数合约,选择切换策略,选择上面的策略 就会出现问题 100%出现
6900行 两次平多
还有一个可能
你系统不是双向交易
开多会先平掉空单
开空会先平掉多单
只有这两种情况
看下我发的新的帖子 https://bbs.tbquant.net/thread/20250616230800333174
我已经将问题定位出来了,里面有DEMO可以直接复现。 多品种的情况下会有重复执行同一根K线的情况,所以导致了MarketPosition() 获取到的状态不对
那就还是我前面说的问题啊
序列变量就这个特征
一个是对机制理解的问题
不能说你错了或者理解不对
但是你的编码
是onbar就把所有数据源止盈一遍
tbq机制又限定了
第一个帖子就明确说了
接受他
还有一个可能
你系统不是双向交易
开多会先平掉空单
开空会先平掉多单
只有这两种情况
前面帖子直接告诉你了
还没明白?
序列变量是上个bar继承传递过来的
当前bar不会变
第二个tick过来又回去了
MarketPosition是否有问题,你可以描述为几时几分哪个图表哪个K线,起始时间是什么
MarketPosition当下值是多少,应该是多少?
我提供的LOG图上是有的啊 ,选的是日线的图,时间 是20140106,合约是zn999.TBFT,在6900行平多之后 MarketPosition得到的状态是0,6906行又进行了一次平多操作,在进行平多之前 得到的状态是1。 这两个就对不上了
zn999.TBFT 是沪锌指数
在6900行平多之后 MarketPosition得到的状态是0,这个时候 6906行 不应该进行再次平多因为MarketPosition得到的状态是0,但是6906行又进行了一次平多操作,在进行平多之前此时MarketPosition应该为1才对,6906行的平多操作不应该存在。
我刚刚说错了,用简短的话说明一下 就是 平多之后MarketPosition的状态是0,但是后面又变成了1,对应的 LOG图里面 就是 6900 和 6905行
时间 20140106 合约=zn999.TBFT 的bar被执行了两次
逻辑上讲,marketposion是不会倒退的
但是你的全局变量只要一个地方出错就全部出错
你这个情况,这个range加全局,第一时间怀疑的方向就是别的图层触发导致全局变量错误。
你还要告诉我要怎么复现,几个图层,品种,起始时间,哪根K线触发的
老师换个角度看一下 本质是时间 20140106 合约=zn999.TBFT 的bar被执行了两次,所以这个时候marketposion获取到的状态没有变化
关于 你还要告诉我要怎么复现,几个图层,品种,起始时间,哪根K线触发的
这些题干里面都有说明的 先打开螺纹钢指数合约的K线,缩小到最早的时间,2009年,然后添加沪铅 沪锡 沪锌 指数合约 ,触发事件是 20140106