/*
------------------------------------------------------------------------
简称: Test_For_BuySell
名称: 测试BuySell及MarketPosition图表信号执行逻辑
测试品种: rb2210、ag2206
测试周期:1分钟
测试结论:
1、MarketPosition及BuySell属于图表交易模式,在当前Bar为了保证信号不闪烁BuySell必须反复执行来确认图表信号有效,并改变MarketPosition的值
2、MarketPosition为序列变量,其当前Bar初值为前一根Bar的终值
3、除BuySell外的代码如果不想被反复执行,可以通过全局状态变量来进行处理
4、如果BuySell都不想反复执行,那就不能用图表系统,只能用A函数+Global状态变量来解决
------------------------------------------------------------------------
*/
Params
Numeric fastLength(3);
Numeric slowLength(5);
Numeric myPos(1);
Vars
Global Integer tickCounter(0); // tick计数器
Global Integer BuySellCounter(0); // BuySell在当前Bar运行次数计数器
Global Integer orderBarIndex; // BuySell执行Bar的索引值
Bool ret;
Bool isOrderBar(False);
Series<Numeric> fastMA;
Series<Numeric> slowMA;
Series<Numeric> a_EntryPrice;
Series<Numeric> a_EntryPos;
Series<Numeric> a_ExitPrice;
Events
OnInit()
{
orderBarIndex = InvalidInteger ;
}
OnBar(ArrayRef<Integer> indexs)
{
Print("[ tickCounter: " + Text(tickCounter) + " ]");
If(orderBarIndex != CurrentBar) BuySellCounter = 0;
//Print("[" + Text(tickCounter) + "]orderBarIndex = " + Text(orderBarIndex));
fastMA = AverageFC(Close[1],fastLength);
slowMA = AverageFC(Close[1],slowLength);
// 开仓
If(MarketPosition == 0)
{
If(Open > fastMA && fastMA > slowMA)
{
a_EntryPrice = Open;
a_EntryPos = myPos;
ret = Buy(a_EntryPos, a_EntryPrice); // 通过每次执行BuySell发送图表信号,从而改变MarketPosition的值
If(ret)
{
orderBarIndex = CurrentBar; // 记录BuySell当前Bar的索引值
BuySellCounter = BuySellCounter + 1; // 每执行一次BuySell计数器+1
Print("[Buy]MarketPosition = " + Text(MarketPosition));
Print("BuySellCounter = " + Text(BuySellCounter));
If(BuySellCounter==1)
{
// 这里放不想被反复执行的部分代码,例如写入log
Print("这段代码当前Bar只会执行一次!");
}
}
}
If(Open < fastMA && fastMA < slowMA)
{
a_EntryPrice = Open;
a_EntryPos = myPos;
ret = SellShort(a_EntryPos, a_EntryPrice);
If(ret)
{
orderBarIndex = CurrentBar;
BuySellCounter = BuySellCounter + 1;
Print("[SellShort]MarketPosition = " + Text(MarketPosition));
Print("BuySellCounter = " + Text(BuySellCounter));
If(BuySellCounter==1)
{
// 这里放不想被反复执行的部分代码,例如写入log
Print("这段代码当前Bar只会执行一次!");
}
}
}
}
// 处理多头持仓
If(MarketPosition == 1 && !isOrderBar)
{
If(fastMA < slowMA)
{
a_ExitPrice = Open ;
ret = Sell(a_EntryPos, a_ExitPrice);
If(ret)
{
orderBarIndex = CurrentBar;
BuySellCounter = BuySellCounter + 1;
Print("[Sell]MarketPosition = " + Text(MarketPosition));
Print("BuySellCounter = " + Text(BuySellCounter));
If(BuySellCounter==1)
{
// 这里放不想被反复执行的部分代码,例如写入log
Print("这段代码当前Bar只会执行一次!");
}
}
}
}
// 处理空头持仓
If(MarketPosition == -1 && !isOrderBar)
{
If(fastMA > slowMA)
{
a_ExitPrice = Open ;
ret = BuyToCover(a_EntryPos, a_ExitPrice);
If(ret)
{
orderBarIndex = CurrentBar;
BuySellCounter = BuySellCounter + 1;
Print("[BuyToCover]MarketPosition = " + Text(MarketPosition));
Print("BuySellCounter = " + Text(BuySellCounter));
If(BuySellCounter==1)
{
// 这里放不想被反复执行的部分代码,例如写入log
Print("这段代码当前Bar只会执行一次!");
}
}
}
}
// 图表均线
PlotNumeric("fastMA", fastMA, fastMA, White);
PlotNumeric("slowMA", slowMA, slowMA, Yellow);
// 计数器
tickCounter = tickCounter + 1;
}
也遇到这个问题,会发生反复开仓问题。
因为MarketPosition是一个序列类型,当BuySell完成开仓时,MarketPosition立刻发生改变不为零,但在实盘过程中当前Bar会多次运行,MarketPosition虽发生改变,但再次运行时被重置为上根Bar的初值(零),MarketPosition==0时开仓代码在同一根Bar会被再次运行。但这种情况在回溯中不会发生,因为每根Bar只运行了一次。
这么理解对吗?
这个描述看起来是对的,但是总感觉怪怪的
呵呵,是吗?可能我学理的中文基础差,哪里奇怪?
我主要考虑要不要加状态变量的问题,BuySell还好办,A函数的话可能就要谨慎点了
还有啊,咱们软件没有问题,我一直是TB的忠实拥护者,咱不要有歧义理解哇 :)
我的意思是,感觉你对这个机制的理解好像有点误会,但是说不出来是什么误会。
可能要通过很多实例才能确定有没有理解吧。
就现在而已,你的描述是正确的
ok,知道目前正确就可以了,应该学的东西太多,只要程序能跑通,就不太抠细节了
我终于明白你说的意思了,又测试了几次,这么理解是有点怪,我现在也说不上来为什么怪了,貌似这个程序必须这么运行,开仓的那段代码必须反复执行才对,才合乎逻辑。我还没有完全理清思路,每次程序运行除了Global外,全部被还原为初始值,序列变量被还原为前值,开仓代码如果不能反复执行,可能反而会导致开仓出问题。
我尝试做一个状态变量,标记程序已经执行过一次BuySell,结果MarketPosition的问题是解决了,开仓代码也不会被反复执行了,但出现了信号闪烁的问题。BuySell这里有一个重要的任务,就是必须改变MarketPosition的值,否则MarketPosition就会是初值0,从而发生信号闪烁,所以程序每次执行都必须走一边BuySell。这个逻辑貌似是卡在这里,BuySell和MarketPosition的图表信号逻辑,是根本原因。
这个描述看起来就比较对了
也不是都是初始值,序列类型会复原成为上一根bar的运算结果,其他容器会重置
是的,我已经把最终的回测代码发出来了,这个问题圆满解决
// 在实时行情策略发出开仓信号的情况下,当前Bar的MarketPosition值不会立刻改变,而是在下一根Bar发生改变
如果想要验证这个想法,那肯定是发出开仓信号前,输出一下marketposition的值,然后发出开仓信号后,马上再输出一下marketposition的值,也就是要在buy和sellshort命令前后都紧挨着加上输出语句,
原文给的代码里,我没看到任何这样的操作,我不知道这样能验证出来什么?
你们如果不喜欢用commentary,那用fileappend也行,代码如下
Vars
Numeric h4w;
Numeric l4w;
Events
OnBar(ArrayRef<Integer> indexs)
{
h4w = highest(high[1],20);
l4w = lowest(low[1],20);
If(high>=h4w and MarketPosition<>1)
{
//Commentary("执行前marketposition="+text(MarketPosition));
FileAppend(FormulaName,"----------分隔符----------");
FileAppend(FormulaName,"执行前marketposition="+text(MarketPosition));
buy(1,max(open,h4w));
//Commentary("执行后marketposition="+text(MarketPosition));
FileAppend(FormulaName,"执行后marketposition="+text(MarketPosition));
}
if(low<=l4w and MarketPosition<>-1)
{
//Commentary("执行前marketposition="+text(MarketPosition));
FileAppend(FormulaName,"----------分隔符----------");
FileAppend(FormulaName,"执行前marketposition="+text(MarketPosition));
sellshort(1,min(open,l4w));
//Commentary("执行后marketposition="+text(MarketPosition));
FileAppend(FormulaName,"执行后marketposition="+text(MarketPosition));
}
}
文件结果
我实在是想不通这么简单的一个问题怎么会有这么多人搞不清楚如何去验证甚至斩钉截铁的说“我试过,确实有问题”
代码如下
Vars
Numeric h4w;
Numeric l4w;
Events
OnBar(ArrayRef<Integer> indexs)
{
h4w = highest(high[1],20);
l4w = lowest(low[1],20);
If(high>=h4w and MarketPosition<>1)
{
Commentary("执行前marketposition="+text(MarketPosition));
buy(1,max(open,h4w));
Commentary("执行后marketposition="+text(MarketPosition));
}
if(low<=l4w and MarketPosition<>-1)
{
Commentary("执行前marketposition="+text(MarketPosition));
sellshort(1,min(open,l4w));
Commentary("执行后marketposition="+text(MarketPosition));
}
}
测试结果
这个是否有验证结果了呢?
我试过,当前Bar的MarketPosition值确实不会立刻改变,会有延迟,开仓超过一次。
我测试也是这个结果,所以才来发帖求证
请把能支持你观点的测试代码发一下
// 在实时行情策略发出开仓信号的情况下,当前Bar的MarketPosition值不会立刻改变,而是在下一根Bar发生改变
这句错误
执行信号命令后,marketposition会立即改变
你可以通过在信号命令前后分别commentary输出marketposition的值来观察
请把代码运行下,我昨天测试时,MarketPosition 在当前Bar发生交易时,的确没有改变值,而是延后一个Bar才改变。我在开仓后写log的时候发现这个问题,可能BuySell本身有过滤反复开仓的机制,并没有不断开仓,但log却在不断的写入,说明代码确实被反复执行了,这里如果是个A函数,那应该就会不断开仓了。
你这个代码又输出不了日志,运行有什么用?
marketposition是一个序列类型,当每次程序驱动运行的时候,初值是上一根bar的运行结果,不是上一tick的运行结果