Params
Numeric dkx_k1(10); // 多空线
Numeric dkx_k2(10); // 多空线
Enum<String> lots_mode(["资金占比","持仓市值","固定手数"]); // 开仓手数计算类型
Integer fixed_lots(1); // 固定手数
Numeric fixed_money(100000); // 固定市值
Numeric money_rate(0.1); // 资金比例,0.1=10%
bool is_rollover(True); // 是否还原复权前价格
Vars
//此处添加变量
Series<Numeric> dkx_a;
Series<Numeric> dkx_b;
Series<Numeric> dkx_d;
bool is_over;
bool is_under;
bool cross_over;
bool cross_under;
Series<Numeric> dkxcd_diff;
Numeric dkxcd_avg;
Numeric dkxcd_value;
Integer lots_num;
Global Integer cur_lot(0);
Defs
Integer CalcuTradeLots() // 交易手数计算函数
{
Integer myLots;
if(lots_mode=="资金占比")
{
myLots = Max(1,IntPart((Portfolio_CurrentEquity*money_rate/MarginRatio)/(Open*contractunit*bigpointvalue)));
}
else if(lots_mode=="持仓市值")
{
myLots = Max(1,IntPart(fixed_money/(Open*contractunit*bigpointvalue)));
}
else if(lots_mode=="固定手数")
myLots = fixed_lots;
else
myLots = fixed_lots;
return myLots;
}
Events
OnInit()
{
Range[0:DataCount-1]
{
if (is_rollover)
{
AddDataFlag(Enum_Data_RolloverBackWard()); //设置后复权
AddDataFlag(Enum_Data_RolloverRealPrice()); //设置映射真实价格
AddDataFlag(Enum_Data_AutoSwapPosition()); //设置自动换仓
AddDataFlag(Enum_Data_IgnoreSwapSignalCalc()); //设置忽略换仓信号计算
SetOrderMap2MainSymbol(); //设置委托映射到主力
}
}
}
//Bar更新事件函数,参数indexs表示变化的数据源图层ID数组
OnBar(ArrayRef<Integer> indexs)
{
data0.lots_num = CalcuTradeLots();
//计算多空线
// 短周期
data0.dkx_a = (3*data0.Close[0]+data0.Low[0]+data0.Open[0]+data0.High[0])/6;//3倍收盘价与最高价、最低价、开盘价之和的均值。
data0.dkx_b = data0.WAverage(data0.dkx_a, 2*dkx_k1);
data0.dkx_d = data0.Average(data0.dkx_b, dkx_k1);//对B值做10周期平均计算。
data0.cross_over = data0.CrossOver(data0.dkx_b, data0.dkx_d);
data0.cross_under = data0.CrossUnder(data0.dkx_b, data0.dkx_d);
data0.is_over = data0.dkx_b > data0.dkx_d;
data0.is_under = data0.dkx_b < data0.dkx_d;
// 中周期
data1.dkx_a = (3*data1.Close[0]+data1.Low[0]+data1.Open[0]+data1.High[0])/6;//3倍收盘价与最高价、最低价、开盘价之和的均值。
data1.dkx_b = data1.WAverage(data1.dkx_a, 2*dkx_k2);
data1.dkx_d = data1.Average(data1.dkx_b, dkx_k2);//对B值做10周期平均计算。
data1.cross_over = data1.CrossOver(data1.dkx_b, data1.dkx_d);
data1.cross_under = data1.CrossUnder(data1.dkx_b, data1.dkx_d);
data1.is_over = data1.dkx_b > data1.dkx_d;
data1.is_under = data1.dkx_b < data1.dkx_d;
//短周期开仓
if (data0.MarketPosition <= 0)
{
if (data0.is_over and data1.is_over and cur_lot == 0)
{
print("##### time : " + Text(Time));
print("marketPosition : " + Text(data0.MarketPosition));
print("cur_lot : " + Text(cur_lot));
data0.Buy(data0.lots_num, data0.Close);
cur_lot = 1;
Print("buy");
print("marketPosition : " + Text(data0.MarketPosition));
print("cur_lot : " + Text(cur_lot));
}
}
if (data0.MarketPosition >= 0)
{
if (data0.is_under and data1.is_under and cur_lot == 0)
{
print("##### time : " + Text(Time));
print("marketPosition : " + Text(data0.MarketPosition));
print("cur_lot : " + Text(cur_lot));
data0.SellShort(data0.lots_num, data0.Close);
cur_lot = 1;
Print("SellShort");
print("marketPosition : " + Text(data0.MarketPosition));
print("cur_lot : " + Text(cur_lot));
}
}
//平仓
if (data0.MarketPosition > 0)
{
//技术 止损 止盈
if (data0.cross_under)
{
Commentary("cross_under 0");
Commentary("Sell 0");
data0.Sell(0, data0.Close);
}
}
else if(data0.MarketPosition < 0)
{
//技术 止损 止盈
if (data0.cross_over)
{
Commentary("cross_over 0");
Commentary("BuyToCover 0");
data0.BuyToCover(0, data0.Close);
}
}
//画图
data0.PlotNumeric("b0", data0.dkx_b);
data0.PlotNumeric("d0", data0.dkx_d);
data0.PlotNumeric("b1", data1.dkx_b);
data0.PlotNumeric("d1", data1.dkx_d);
data1.PlotNumeric("b1", data1.dkx_b);
data1.PlotNumeric("d1", data1.dkx_d);
}
//下一个Bar开始前,重新执行当前bar最后一次,参数为当前bar的图层数组
OnBarClose(ArrayRef<Integer> indexs)
{
cur_lot = 0;
}
请问为什么这个会频繁开仓,我是通过cur_lot来控制每条K线只开一次仓,为了防止信号闪烁。我看到确实开仓成功了,然后下一条K线的时候还继续开仓,那是为什么呢,我已经是有marketPosition判断了。
用全局变量来控制下个Tick不产生信号,为什么会导致信号消失?
我说下正常的公式机制,以单数据源为例,历史K线公式运行一次,实时K线每个tick运行一次,如果某个Tick满足交易条件,发出交易信号,系统会同时发送委托。正常情况下,只要发出交易信号了,后续的Tick也要能继续满足交易条件了,这样信号就可以保持到这根K线结束。这样将来这根BAR成为历史K线了,根据交易条件也是满足交易条件的,这个信号就不会出现闪烁。测试结果和实际交易结果就是一样的。这是正确编写的公式的运行和回测的状态。
然后说下有问题的策略写法。某个Tick满足交易条件,发出交易信号,系统会同时发送委托。但是后续Tick有可能不满足交易条件了,导致信号没有了,但系统发出的单子是铁定已经成交了的。这种情况就叫信号消失。因为一般不满足交易条件,都是因为交易后不利导致的,所以这样写策略导致的结果就是,只要交易不利,就会把产生过的信号抹掉,只有有利的交易才会留下,这样测试结果会非常好。但实际交易能抹掉吗?肯定不能,所以这种策略也叫使用未来数据,是我们尽量要规避的。
现在您的策略是怎么写的呢?成交了,我就用全局变量让它下个Tick不产生信号。这不是故意往我们要规避的错误的方向去吗?所以,我说您没有搞清楚公式机制。
谢谢,我思考一下。
//------------------------------------------------------------------------
// 简称: DKXTrade
// 名称: 多空线交易策略
// 类别: 公式应用
// 类型: 用户应用
// 输出: Void
// 策略说明:多空线趋势策略
// 系统要素:
// 1. 短周期多空线
// 2. 中周期多空线
// 3. 长周期多空线
// 入场条件:
// 短周期与长周期同方向
// 短周期金叉或死叉的时候
// 长周期金叉或死叉的时候
// DKXCD 超过阈值 并且在0轴上方下方
// 出场条件:
// 短周期金叉或死叉的时候
//
//------------------------------------------------------------------------
Params
Numeric dkx_k1(10); // 多空线
Numeric dkx_k2(10); // 多空线
Numeric dkxcd_length(9); // 平滑异步多空线
Numeric dkxcd_threshold(2.5); // 平滑异步多空线阈值
Enum<String> lots_mode(["资金占比","持仓市值","固定手数"]); // 开仓手数计算类型
Integer fixed_lots(1); // 固定手数
Numeric fixed_money(100000); // 固定市值
Numeric money_rate(0.1); // 资金比例,0.1=10%
bool is_rollover(True); // 是否还原复权前价格
bool is_cut(False); // 是否强制止损
Vars
//此处添加变量
Series<Numeric> dkx_a;
Series<Numeric> dkx_b;
Series<Numeric> dkx_d;
bool is_over;
bool is_under;
bool cross_over;
bool cross_under;
Series<Numeric> dkxcd_diff;
Numeric dkxcd_avg;
Numeric dkxcd_value;
Integer lots_num;
Global Integer cur_pos(0); //当前k线的单子方向
Global Integer cur_lot(0); //当前k线的单子手数
Global Integer cur_price(0); //当前k线的单子价格
Defs
Integer CalcuTradeLots() // 交易手数计算函数
{
Integer myLots;
if(lots_mode=="资金占比")
{
myLots = Max(1,IntPart((Portfolio_CurrentEquity*money_rate/MarginRatio)/(Open*contractunit*bigpointvalue)));
}
else if(lots_mode=="持仓市值")
{
myLots = Max(1,IntPart(fixed_money/(Open*contractunit*bigpointvalue)));
}
else if(lots_mode=="固定手数")
myLots = fixed_lots;
else
myLots = fixed_lots;
return myLots;
}
Events
OnInit()
{
Range[0:DataCount-1]
{
if (is_rollover)
{
AddDataFlag(Enum_Data_RolloverBackWard()); //设置后复权
AddDataFlag(Enum_Data_RolloverRealPrice()); //设置映射真实价格
AddDataFlag(Enum_Data_AutoSwapPosition()); //设置自动换仓
AddDataFlag(Enum_Data_IgnoreSwapSignalCalc()); //设置忽略换仓信号计算
SetOrderMap2MainSymbol(); //设置委托映射到主力
}
}
}
//Bar更新事件函数,参数indexs表示变化的数据源图层ID数组
OnBar(ArrayRef<Integer> indexs)
{
data0.lots_num = CalcuTradeLots();
//计算多空线
// 短周期
data0.dkx_a = (3*data0.Close[0]+data0.Low[0]+data0.Open[0]+data0.High[0])/6;//3倍收盘价与最高价、最低价、开盘价之和的均值。
data0.dkx_b = data0.WAverage(data0.dkx_a, 2*dkx_k1);
data0.dkx_d = data0.Average(data0.dkx_b, dkx_k1);//对B值做10周期平均计算。
data0.cross_over = data0.CrossOver(data0.dkx_b, data0.dkx_d);
data0.cross_under = data0.CrossUnder(data0.dkx_b, data0.dkx_d);
data0.is_over = data0.dkx_b > data0.dkx_d;
data0.is_under = data0.dkx_b < data0.dkx_d;
// 中周期
data1.dkx_a = (3*data1.Close[0]+data1.Low[0]+data1.Open[0]+data1.High[0])/6;//3倍收盘价与最高价、最低价、开盘价之和的均值。
data1.dkx_b = data1.WAverage(data1.dkx_a, 2*dkx_k2);
data1.dkx_d = data1.Average(data1.dkx_b, dkx_k2);//对B值做10周期平均计算。
data1.cross_over = data1.CrossOver(data1.dkx_b, data1.dkx_d);
data1.cross_under = data1.CrossUnder(data1.dkx_b, data1.dkx_d);
data1.is_over = data1.dkx_b > data1.dkx_d;
data1.is_under = data1.dkx_b < data1.dkx_d;
//短周期开仓
if (cur_pos == 0)
{
if (data0.MarketPosition <= 0)
{
if (data0.is_over and data1.is_over and cur_pos == 0)
{
data0.Buy(data0.lots_num, data0.Close);
cur_pos = 1;
cur_lot = data0.lots_num;
cur_price = data0.Close;
}
}
if (data0.MarketPosition >= 0)
{
if (data0.is_under and data1.is_under and cur_pos == 0)
{
data0.SellShort(data0.lots_num, data0.Close);
cur_pos = -1;
cur_lot = data0.lots_num;
cur_price = data0.Close;
}
}
}
//平仓
if (cur_pos == 0)
{
if (data0.MarketPosition > 0)
{
//技术 止损 止盈
if (data0.cross_under)
{
Commentary("cross_under 0");
Commentary("Sell 0");
data0.Sell(0, data0.Close);
cur_pos = 1;
cur_lot = 0;
cur_price = data0.Close;
}
}
else if(data0.MarketPosition < 0)
{
//技术 止损 止盈
if (data0.cross_over)
{
Commentary("cross_over 0");
Commentary("BuyToCover 0");
data0.BuyToCover(0, data0.Close);
cur_pos = -1;
cur_lot = 0;
cur_price = data0.Close;
}
}
}
// 当前K线开仓平仓之后保持开仓信号
if (cur_pos == 1)
{
if (cur_lot > 0)
data0.Buy(cur_lot, cur_price);
else
data0.Sell(0, cur_price);
}
else if (cur_pos == -1)
{
if (cur_lot > 0)
data0.SellShort(cur_lot, cur_price);
else
data0.BuyToCover(0, cur_price);
}
//画图
data0.PlotNumeric("b0", data0.dkx_b);
data0.PlotNumeric("d0", data0.dkx_d);
data0.PlotNumeric("b1", data1.dkx_b);
data0.PlotNumeric("d1", data1.dkx_d);
data1.PlotNumeric("b1", data1.dkx_b);
data1.PlotNumeric("d1", data1.dkx_d);
}
//下一个Bar开始前,重新执行当前bar最后一次,参数为当前bar的图层数组
OnBarClose(ArrayRef<Integer> indexs)
{
// 当k线结束后清理当前k线的信号
cur_pos = 0;
cur_lot = 0;
cur_price = 0;
}
//------------------------------------------------------------------------
// 编译版本 2021/07/04 230331
// 版权所有 suyesheng
// 更改声明 TradeBlazer Software保留对TradeBlazer平台
// 每一版本的TradeBlazer公式修改和重写的权利
//------------------------------------------------------------------------
你好,我对代码进行了修改,这样貌似就能在当前k线触发信号之后阻止信号的消失了吧
粗略看了下,您这大段代码中,关键的地方还是没有改——不能用全局变量来人为地让下一个Tick不满足交易条件。
您好!看了一遍公式,您的问题是对公式运行机制没了解清楚。BuySell指令要求在一根BAR中的信号产生后不能消失,信号产生后每个Tick运行都要保持信号的存在,这种同一BAR的多个Tick运行产生的信号并不会像你想象的导致重复发单。反倒是您想用全局变量来控制下个Tick不产生信号,会导致信号消失。所以,就会开仓成功后,信号消失了。下根BAR又继续开仓。另外您的公式中,用Close来做判断是会产生信号消失的,不能这么用
请问用全局变量来控制下个Tick不产生信号,为什么会导致信号消失?
信号消失的意思就是同一根bar上,前面的tick使信号满足,后面的tick使信号不满足,导致前面出现信号,后面不出现信号,直观上就像信号消失了一样。