之前刘风老师在视频课程时提供了一串防止跨图层信号闪烁的数据对齐代码,可以放在ONBAROPEN、ONBAR、ONBARCLOSE事件域的开头:
Numeric i;
Numeric result=1;
for k=0 to DataSourceSize-1
{
result= result*data[i].BarExistStatus;
}
If(result<>1) Return;
----但是,加载的品种里如果晚盘时没有开盘怎么办?比如鸡蛋,晚盘没有行情,TB会判断它没有来TICK数据,BarExistStatus一直等于2,导致程序在晚盘的时间在这串代码一直返回。
期待回复,谢谢
刘风老师,是这样的。因为我这是一个截面策略,叠加没有夜盘的品种,其实目的不是让没有夜盘的品种出信号,而是加载的品种之间需要在同一根BAR的截面上取CLOSE[1]计算一个全局变量指标,这个全局变量指标在对所有品种的信号计算是有作用的。在历史回测的时候,取非夜盘品种的CLOSE[1]会自动跳过非夜盘时间段往前回溯取值,而实盘时我想达到同样的效果。
况且,即使对于有夜盘的品种来说,交易时间段也是不一样的。比如白银开盘到晚上2:30,螺纹钢开盘到晚上11点,那么白银在11点至2:30分之间,也会因为螺纹钢的交易时间已经结束,BarExistStatus==2,程序也会在11点后不再运行。
所以,这个需求可以怎么实现呢?谢谢老师
你既然是横截面策略,而且需要所有品种的close【1】来计算全局指标,那么到夜盘时间,你这个指标因为没有无夜盘品种的数据参与,那不就是计算无效了么?那还计算它干嘛呢?难道不是应该等到所有品种都有数据才计算吗?只要有一个品种返回交易时间无效,那就不应该计算
刘风老师,可能问题并不在这里,因为我也试过把所有非夜盘品种都去掉,把白银黄金品种去掉,只留下交易时间段完全一样的品种,用上防信号闪烁那串数据对齐的代码,即使在白天交易时间段,也是会出现信号消失(表现为:监控器在实盘时不会显示不匹配,但一旦把策略单元停止并重启后,监控器即刻查出不匹配)。不匹配的原因有两种:要么是实盘委托了,事后查看图表没有信号。或者图表交易有信号,但实盘并不报单),看起来是很典型的信号闪烁或者信号消失问题。
我把策略代码贴上来,代码不多,逻辑也不复杂。麻烦您帮我看一下行吗,因为问题困扰我很久了,谢谢!贴过来的代码在贴子里好像格式对不齐,见谅!
Params
Bool IsRollover(true);//是否后复权
Bool IsRolloverRealPrice(true);//是否映射真实价格
Bool IsAutoSwapPosition(true);//是否自动换仓
Numeric Fund(167000);//下单金额
Numeric N(25);//回溯周期
Numeric instNum(36);//品种数量 ,
Numeric WeekdaySet(2);//选择星期几交易
Numeric TimeSet(0.10);//选择哪个时间点交易
Numeric FEN(1);//用来取指标值排名第一和排名最后的参数
Vars
Global Array<Numeric> RR;//因子值
Global Array<Numeric> RS;//保存因子值的变量
//NumericArray atr;
Numeric i;
Numeric k;
Numeric j;
Global Array<Numeric> lots;//下单手数
Global Array<Numeric> myclose;
Series<Numeric> RRup;
Series<Numeric> RRdown;
Integer status;
Events
//此处实现事件函数
//初始化事件函数,策略运行期间,首先运行且只有一次,应用在订阅数据等操作
OnInit()
{
Range[0:DataCount-1]
{
If(IsRollover)
{
AddDataFlag(Enum_Data_RolloverBackWard());//设置后复权
}
If(IsRolloverRealPrice)
{
AddDataFlag(Enum_Data_RolloverRealPrice());//是否映射真实价格
}
If(IsAutoSwapPosition)
{
AddDataFlag(Enum_Data_AutoSwapPosition());//设置自动换仓
}
}
SetGlobalVar2(\"Switch\", 0);
//GetGlobalVar2(\"Switch\")
}
//在新bar的第一次执行之前调用一次,参数为新bar的图层数组
OnBarOpen(ArrayRef<Integer> indexs)
{
Numeric k;
Numeric result=1;
for k=0 to DataSourceSize-1
{
result= result*data[k].BarExistStatus;
}
If(result<>1) Return;
If(DATA[i].Rollover<>DATA[i].Rollover[1])
PlotBool(\"true\",True);
//If(QuoteStatus() != 1) Return;//过滤集合竞价
Commentary(\"当前bar的时间\"+text(date+time));
//If(data!=data[1]and high==low) Return;
//使用FOR循环,品种编号,全部使用索引
//#############################################数据获取计算部份##################################
Commentary(\"当前bar的时间\"+text(date+time));
For i = 0 to instNum-1
{
if(data[i].close[1]==data[i].close[2]&&data[i].close[2]==data[i].close[3]&&data[i].close[3]==data[i].close[4])
{
RR[i]=10000000;//对于未上市的品种,将因子值赋予相对无限大,使其升序排序时不影响后面的交易
Commentary(\"data \"+text(i)+\" 出问题\"+text(date+time));
//print(\"data \"+text(i)+\" 出问题\"+text(date+time));
}
else
{
Numeric mysummation;
mysummation=summation(Abs(data[i].close[2]-data[i].close[3]),N);
RR[i]=(data[i].close[1]-data[i].close[N])/mysummation;//ER因子
k=k+1;
//print(\"status = \"+text(status));
}
myclose[i]=data[i].close[1]/data[i].Rollover;
lots[i]=(Fund+Portfolio_TotalProfit())/(myclose[i]*data[i].ContractUnit*data[i].BigPointValue*data[i].MarginRatio);
data[i].Commentary(\"lots[i]=\"+text(lots[i]));
}
Commentary(\"k = \"+Text(k));
RS=RR;//用RS值来保存原始的因子值RR数组
Commentary(\"RS=\"+TextArray(RS));
//对因子值进行排序,排序后RR数组本身会发生改变
ArraySort(RR,True);
//截取33%,66%分位数的因子值
j=MAX(1,FEN);
RRup=RR[j-1];//得到排名前33%
RRdown=RR[k-j];//得到排名后33%
Commentary(\"RR=\"+TextArray(RR));
Commentary(\"j = \"+Text(j));
Commentary(\"RRup=\"+Text(RRup));
Commentary(\"RRdown=\"+Text(RRdown));
Commentary(\"Time=\"+Text(Time));
k =0;
Commentary(\"RR1111=\"+TextArray(RR));
////#############################################循环交易下单执行部份##################################
Numeric Temp_RRup=RRup;
Numeric Temp_RRdown=RRdown;
For i=0 to instNum-1
{
//做多排名第一的品种
If( RS[i]>=Temp_RRdown AND RS[i]!=10000000 AND data[i].MarketPosition!=1 AND Weekday==WeekdaySet and time==TimeSet)
{
print(\"当前bar1 \"+text(Time));
IF(data[i].MarketPosition==0)
{
DATA[i].Buy(Lots[i],data[i].Open);
}
Else IF(data[i].MarketPosition==-1)
{
DATA[i].BuyToCover(0,DATA[i].open);
DATA[i].Buy(Lots[i],data[i].Open);
}
}
//做空排名最后的品种
If( RS[i]<=Temp_RRup AND RS[i]!=10000000 AND data[i].MarketPosition!=-1 AND Weekday==WeekdaySet AND time==TimeSet)
{
print(\"当前bar2 \"+text(Time));
IF(data[i].MarketPosition==0)
{
DATA[i].SellShort(Lots[i],data[i].Open);
}
Else IF(data[i].MarketPosition==1)
{
DATA[i].Sell(0,DATA[i].open);
DATA[i].SellShort(Lots[i],data[i].Open);
}
}
//除了第一和最后,其它品种空仓
If(RS[i]>Temp_RRup AND RS[i]<Temp_RRdown AND DATA[i].MarketPosition==1 AND Weekday==WeekdaySet AND time==TimeSet)
{
print(\"当前bar3 =\"+text(Time));
DATA[i].Sell(0,DATA[i].open);
}
If(RS[i]==10000000 AND DATA[i].MarketPosition==1 AND Weekday==WeekdaySet AND time==TimeSet)
{
print(\"当前bar4 \"+text(Time));
DATA[i].Sell(0,DATA[i].open);
}
If (RS[i]>Temp_RRup AND RS[i]<Temp_RRdown AND DATA[i].MarketPosition==-1 AND Weekday==WeekdaySet AND time==TimeSet)
{
print(\"当前bar5 \"+text(Time));
DATA[i].BuyToCover(0,DATA[i].open);
}
If(RS[i]==10000000 AND DATA[i].MarketPosition==-1 AND Weekday==WeekdaySet AND time==TimeSet)
{
print(\"当前bar6 \"+text(Time));
DATA[i].BuyToCover(0,DATA[i].open);
}
}
}
//Bar更新事件函数,参数indexs表示变化的数据源图层ID数组
OnBar(ArrayRef<Integer> indexs)
{
}
//下一个Bar开始前,重新执行当前bar最后一次,参数为当前bar的图层数组
OnBarClose(ArrayRef<Integer> indexs)
{
}
一般来说,图层信号闪烁用在跨周期上,不会有跨品种的交易时间不对齐的问题。
你现在需要跨品种交易,那么不要把交易时间不对齐的品种放在一起。
如果一定要放在一起,那么你自己要考虑清楚,既然是要放在一起,那么说明需要互相引用不同品种的数据,那么如果有夜盘的品种,需要无夜盘的品种数据,那么有夜盘的品种,夜盘时间为什么会出信号?无夜盘品种都没开盘,怎么会给出信号?对齐还有什么意义?那如果你不需要引用不同品种的数据,那又何必放在一个单元里做图层叠加呢?
刘风老师,是这样的。因为我这是一个截面策略,叠加没有夜盘的品种,其实目的不是让没有夜盘的品种出信号,而是加载的品种之间需要在同一根BAR的截面上取CLOSE[1]计算一个全局变量指标,这个全局变量指标在对所有品种的信号计算是有作用的。在历史回测的时候,取非夜盘品种的CLOSE[1]会自动跳过非夜盘时间段往前回溯取值,而实盘时我想达到同样的效果。
况且,即使对于有夜盘的品种来说,交易时间段也是不一样的。比如白银开盘到晚上2:30,螺纹钢开盘到晚上11点,那么白银在11点至2:30分之间,也会因为螺纹钢的交易时间已经结束,BarExistStatus==2,程序也会在11点后不再运行。
所以,这个需求可以怎么实现呢?谢谢老师