前两天我发了关于 MarketPosition() 获取到的状态不对 的帖子
https://bbs.tbquant.net/thread/20250613174746908464
https://bbs.tbquant.net/thread/20250616152306846672
经过测试我将问题定位了出来 ,一个小DEMO就可以确定复现, 多品种的情况下会有重复执行同一根K线的情况
Vars
Natural CodeProperty codePro;
Global Array<Numeric> lastTradeBars; // 记录每个品种的最后交易Bar索引
Global Numeric j; // 自增计数
Events
OnReady()
{
SetArraySize(lastTradeBars, DataSourceSize(), -1); // 初始化数组,大小为品种数量,初始值为-1
Range[0:DataSourceSize()-1]
{
GetProperty(codePro);
}
print("OnReady结束");
}
OnBar(ArrayRef<Integer> indexs)
{
Numeric i;
Range[i=0:DataSourceSize()-1]
{
j=j+1;
Print("时间=" + Text(Date)+"当前Bar=" + Text(CurrentBar()) + ", 合约=" + codePro.symbol + "数组="+TextArray(lastTradeBars)+" i="+Text(i)+" 自增j="+Text(j));
// 如果当前Bar索引等于该品种上次交易Bar索引,跳过
If(CurrentBar() == lastTradeBars[i] &&lastTradeBars[i]>0)
{
Print("时间=" + Text(Date)+"当前Bar=" + Text(CurrentBar()) + ", 合约=" + codePro.symbol + "数组="+TextArray(lastTradeBars)+" i="+Text(i)+" 自增j="+Text(j)+" 重复执行");
}
// 记录当前Bar索引
lastTradeBars[i] = CurrentBar();
}
}
11997行和12003行 就可以看出来了, 随便选6个品种 回测起始时间2000年就行
可以排除是全局变量没有更新 因为 打印的时间是一样的
麻烦老师花点时间看下 ,我已经将问题定位的很明确了,复制代码即可复现
看了两眼代码,其实问题就是不理解机制,上面这个图表明了对应的执行逻辑
993下面这根什么重复执行,因为上面周期对应都是下面同一根
这是第一根问题,其实还有别的问题,你全局变量赋值,实时按tick执行,逻辑上可能更混乱
首先,多图层下重复执行代码是可能的,因为多品种的交易时间并不对齐。
比如,一个有夜盘的品种a,和没有夜盘的品种b,如果现在是晚上十点,那么读a品种的交易数据,读到的其实a品种下午收盘前的数据,而不是晚上十点的数据。
我们如果更是深入的举例,比如多品种下,我要比较每个品种的某个指标甲的数值,较大的发出交易信号。
那么如果下午14点时,a品种的指标值较大,所以a品种开了仓。但是等夜盘晚上22点,b品种的指标值和a品种的14点指标值比,b品种又比较大了,那是不是a品种的信号就没了呢?导致marketposition出错?
我只测试了回测,在日线级别里面,上市早的品种会先加载bar,然后到了上市晚的品种的时间才会加载晚的品种的bar。 marketposition出错 是因为重复读取了同一个bar意思就是在这个bar上多了好几个TICK 同一个bar内序列变量的值不变,所以导致了marketposition出错
你这个代码我也看下,但是扫一眼内容,你之前描述为marketposition有问题,然后这个代码主要是全局变量,说明问题还是全局变量
然后说在前面的话就是,range加你这个全局,我很难相信不出问题
然后具体是什么问题,需要分析代码
我说一下我的困惑。
你之前提到的说法是,marketposition状态不对,取到的错了。
但是,你提交的这个复现demo,通篇我都没看到marketposition。
先不说其他的,一个没有marketposition的代码,如何说明marketposition取值出错了呢?我不理解
假设 第一根bar 读取到了marketposition 为0 此时满足了策略开仓 开仓函数返回true ,此时再读取marketposition会为1。重复读取bar之后 此时marketposition 还是为0 包括时间也是一样的状态。导致了marketposition 获取到的状态不对。
onbar(...)
{
integer i;
for i = 0 to datacount - 1
{
if(ArrayFind(indexs, i))
{
data[i].xxxxx;
}
}
}
你这样写了试试
你的编码方式本来就会导致问题
其一
数据源先搞两个
更容易观察
其二
把交易设置为双向
自己读取多/空各自头寸,根据多/空头寸开平
不要用marketpostion
其三
静态回溯 逐Bar 和 实际 逐Tick
运行是有差异的
bar内
序列变量值不会变
Range[i=0:DataSourceSize()-1]
这个就是个for循环
少用
对于其一 3个品种发生问题的概率很低,代码在单品种上跑是没问题的
其二
这个能不能给个DEMO或者伪代码 我看软件内所有的策略都是基于单品种的也是根据marketpostion来判断要不要开仓的
其三 BAR内,序列变量值不会变 是这样,你说的没错。
这个没问题啊 i 一直是循环的,不存在重复的情况
老哥能给个Q么,我好跟你沟通下
你按照我上面的代码先改一下
改完就没问题了
其二
把交易设置为双向
自己读取多/空各自头寸,根据多/空头寸开平
不要用marketpostion 不用marketpostion 怎么读头寸呢
我反正是不指望老师了,如果愿意的话可以加个Q聊一下,我本身是程序员,我之前是用文华的 已经实盘了5年了,就是因为文华的多品种回测局限性很大,所以才想试试开拓者。
不用这么想
我至今还有很多问题要请教老师
longCurrentContracts
shortCurrentContracts
我不知道怎么解释
你才能明白
😢
回测级别选择日线级别