null程序化交易策略实现与实例详解
*程序化交易策略实现与实例详解
蔡云华
深圳开拓者科技有限公司内容安排内容安排
通过实例讲解
持仓交易系统的策略与实现
日内交易系统的策略与实现*持仓交易系统的设计要素持仓交易系统的设计要素设计思路:趋势跟踪;
设计原则:捕捉主要的波段行情;
设计细节:减少盘整时的连续亏损和最大资金回撤。
总的原则:
Cut loss short, Let profit run
截短亏损,让利润奔跑! 双均线交叉系统DMACS 双均线交叉系统DMACS交易规则:
如果短期均线上穿长期均线,做多,如原来持有空单,则先平空单,再建多仓
如果短期均线下穿长期均线,做空,如原来持有多单,则先平多单,再建空单
短周期:10
长周期:20
交易头寸暂为1手
* 双均线指标DualMA 双均线指标DualMAParams
Numeric Length1(10);
Numeric Length2(20);
Begin
PlotNumeric("MA1",AverageFC(Close,Length1));
PlotNumeric("MA2",AverageFC(Close,Length2));
End* DMACS版本1 DMACS版本1Params
Numeric Length1(10);
Numeric Length2(20);
Numeric Lots(1);
Vars
NumericSeries MA1;
NumericSeries MA2;
BoolSeries condBuy(false);
BoolSeries condSell(false);
Begin
MA1 = AverageFC(Close,Length1);
MA2 = AverageFC(Close,Length2);
condBuy = CrossOver(MA1,MA2);
condSell = CrossUnder(MA1,MA2);
If (condBuy[1]==true) Buy(Lots,Open);
If (condSell[1]==true) SellShort(lots,Open);
End * DMACS_V1主要交易品种测试结果 DMACS_V1主要交易品种测试结果 DMACS V1存在的问题 DMACS V1存在的问题盈利单利润回吐太多。必须增加追踪止赢的设置 增加追踪止赢 增加追踪止赢以天胶做多为例:
假如,我们在开盘价30000元/吨买入;
追踪止盈 300点(300X5=1500元/吨); 增加参数TrailingStop,默认值设为400;
增加变量MinPoint,用来保存最小变动单位。
MinPoint = MinMove*PriceScale;
增加序列变量HigherAfterEntry,LowerAfterEntry用来保存开仓后的最高价或最低价。
因为我们的入场是以开盘价入场,所以可以实现开仓Bar的止损,但开仓Bar的最高价,不能计入开仓后的最高价,而只能以进场价作为开仓后的最高价。 进场位置和盈利峰值价计算 进场位置和盈利峰值价计算 开盘价
最低价追踪止损价盈利峰值价止损没
被
止
损 开盘价进场的追踪止损 开盘价进场的追踪止损 开盘价
(进场价)最低价追踪止损价以进场价作为盈利峰值价止损 DMACS_V2(1) DMACS_V2(1)Params
Numeric Length1(10);
Numeric Length2(20);
Numeric TrailingStop(400);
Numeric Lots(1);
Vars
NumericSeries MA1;
NumericSeries MA2;
BoolSeries condBuy(false);
BoolSeries condSell(false);
Numeric MinPoint;
Numeric MyPrice;
NumericSeries HigherAfterEntry;
NumericSeries LowerAfterEntry;
Begin
If(BarsSinceEntry >= 1)
{
HigherAfterEntry = Max(HigherAfterEntry[1],High[1]);
LowerAfterEntry = Min(LowerAfterEntry[1],Low[1]);
}* DMACS_V2(2) DMACS_V2(2) MinPoint = MinMove * PriceScale;
MA1 = AverageFC(Close,Length1);
MA2 = AverageFC(Close,Length2);
condBuy = CrossOver(MA1,MA2);
condSell = CrossUnder(MA1,MA2);
If (condBuy[1]==true)
{
Buy(Lots,Open);
HigherAfterEntry = Open;
LowerAfterEntry = HigherAfterEntry;
}
If (condSell[1]==true)
{
SellShort(lots,Open);
HigherAfterEntry = Open;
LowerAfterEntry = Open;
}* DMACS_V2(3) DMACS_V2(3) Commentary("HigherAfterEntry="+Text(HigherAfterEntry));
Commentary("LowerAfterEntry="+Text(LowerAfterEntry));
If(MarketPosition==1)
{
If(Low <= HigherAfterEntry - TrailingStop*MinPoint)
{
MyPrice = HigherAfterEntry - TrailingStop*MinPoint;
If(Open < MyPrice) MyPrice = Open;
Sell(Lots,MyPrice);
}
}Else If(MarketPosition == -1)
{
If(High >= LowerAfterEntry + TrailingStop*MinPoint)
{
MyPrice = LowerAfterEntry + TrailingStop*MinPoint;
If(Open > MyPrice) MyPrice = Open;
BuyToCover(Lots,MyPrice);
}
}
End * DMACS_V2主要交易品种测试结果 DMACS_V2主要交易品种测试结果 DMACS_V2测试总结 DMACS_V2测试总结绝大多数品种,改进后效果都非常显著。
以铜为例,净利润提高了29138元,最大回撤则大幅下降了33707元。
前面我们采用的是固定400点的追踪止损,但对于不同品种或者同一品种的不同历史时段来说,采用统一的追踪止损
标准
excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载
,显然是不太合理的。
因此,我们决定采用当时价格的一定比例来进行追踪止损。为简单设计,我们就以开仓后的盈利峰值价的一定比例作为止损价格。
具体追踪止损的比例,可以进行一定的参数优化
DMACS_V3 DMACS_V3参数部分修改为百分比:
Numeric TrailingStop(100);
追踪止损的相应部分改为:
If(Low <= HigherAfterEntry * (1 – TrailingStop/1000))
{
MyPrice = HigherAfterEntry * (1 – TrailingStop/1000);
…
}
… …
If(High >= LowerAfterEntry * (1 + TrailingStop/1000))
{
MyPrice = LowerAfterEntry * (1 + TrailingStop/1000);
…
} DMACS_V3主要交易品种测试结果 DMACS_V3主要交易品种测试结果 DMACS_V3测试总结 DMACS_V3测试总结测试结果发现,在不优化参数的情况下,和V1版比还是有一定效果,但和V2版比差别不大。
仔细分析原因,我们会发现,追踪止损的回落百分比参数的设置对结果影响很大。
百分比参数设置得大,则盈利回吐比例也大,但大的波段基本能捕捉到。
百分比参数设置得小,则盈利大部分能拿住,但一波大的行情,有可能中途就出场了。
进一步的策略改进 进一步的策略改进进一步的分析,我们还可以发现一些交易进场后不久就有一定的盈利,但最后却以亏损收场; 而赚钱的单,往往进场后,就马上开始盈利; 新的出场策略 新的出场策略基于这种思路,我们完全可以在进场后,设定一个较紧的初始止损,一旦行情朝不利的方向变动,我们即止损出场,等待下次入场机会;
如果止损后,行情又恢复原有趋势,我们可制定相应的再入场规则,以免错失大的波段行情;
而一旦单子开始盈利,达到一定比例,我们立即将止损位调整到保本的位置;
如行情继续朝有利于我们的方向发展,通过追踪止赢策略,将止损价不断上移(或下移)。 出场部分设计 出场部分设计我们使用三种类型的止损设置:
进场后设置初始止损;
有一定盈利后设置保本止损;
盈利增大后使用追踪止盈;
为此,设置三个止损参数:
Numeric InitialStop(20); // 初始止损(千分之N)
Numeric BreakEvenStop(30); // 保本止损(千分之N)
Numeric TrailingStop(50); // 追踪止损(千分之N)
三种止损的代码可以放在一起处理,取最有利的价格作为止损(赢)价。 为了实现追踪止赢,我们有必要
记录
混凝土 养护记录下载土方回填监理旁站记录免费下载集备记录下载集备记录下载集备记录下载
进场后,赢利最高时的价格(赢利峰值价);
设置两个序列变量,分别保存多头赢利峰值价和空头赢利峰值价:
NumericSeries HigherAfterEntry; // 多头盈利峰值价
NumericSeries LowerAfterEntry; // 空头盈利峰值价
传递和比较赢利峰值价
If(BarsSinceEntry >= 1)
{
HigherAfterEntry = Max(HigherAfterEntry[1],High[1]);
LowerAfterEntry = Min(LowerAfterEntry[1],Low[1]);
} Else
{
HigherAfterEntry = HigherAfterEntry[1];
LowerAfterEntry = LowerAfterEntry[1];
}
多头止损部分的代码 多头止损部分的代码// 初始止损
StopLine = EntryPrice * (1-InitialStop/1000);
// 达到保本止损条件,将止损位上移到保本的价位
If (HigherAfterEntry >= EntryPrice * (1+BreakEvenStop/1000))
StopLine = EntryPrice;
// 追踪止损的价位超过保本止损价,止损价随盈利峰值价的上升同步提高
If (StopLine < HigherAfterEntry*(1-TrailingStop/1000))
StopLine = HigherAfterEntry*(1-TrailingStop/1000);
Commentary("止损价:"+Text(StopLine));
// 止损触发
If(Low <= StopLine)
{
MyPrice = StopLine;
If(Open < MyPrice) MyPrice = Open;
Sell(Lots,MyPrice);
bLongStoped = True; // 止损后设置标志
Commentary("Long Position Stoped at "+text(MyPrice));
}
重新进场规则 重新进场规则首先判断大趋势有没有改变?
趋势没变,何时再进场?
行情再创新高(低)时,再次进场;
是否创新高(低),跟出场前赢利峰值价比较。
如何判断大趋势有没有改变?
根据均线交叉情况;
如果当前K线均线未交叉,则趋势取决于上一次均线交叉的方向;
代码如下:
if ( condBuy == false and condSell == false )
{
condBuy = condBuy[1];
condSell = condSell[1];
}
如何区分初次入场和再次入场?
增加两个序列变量分别记录多头止损情况和空头止损情况,进场时根据这两个值来判断是初次进场,还是再次进场,进场后重置这两个值。
BoolSeries bLongStoped(false); // 多头止损情况
BoolSeries bShortStoped(false); // 空头止损情况
止损触发时,进行记录
If(Low <= StopLine)
{
MyPrice = StopLine;
If(Open < MyPrice) MyPrice = Open;
Sell(Lots,MyPrice);
bLongStoped = True; // 止损后设置标志
}
为了判断是否突破前期高点或低点,还需要保留前期的高低点值。这部分可以利用实现追踪止赢的代码
If(BarsSinceEntry >= 1)
{
HigherAfterEntry = Max(HigherAfterEntry[1],High[1]);
LowerAfterEntry = Min(LowerAfterEntry[1],Low[1]);
}
Else
{
HigherAfterEntry = HigherAfterEntry[1];
LowerAfterEntry = LowerAfterEntry[1];
}
初次进场代码 初次进场代码
初次进场
做多初次进场
做空重置标志重置标志 重新进场代码 重新进场代码 止损处理的细节 止损处理的细节无论初次进场还是再次进场,进场后都是把进场价作为开仓后的盈利最高价或最低价。两者的区别之处在于:
初次进场,因为是开盘价进场,可以在开仓Bar实现止损;
而再次入场,因为在历史K线中,无法确定入场点和最高价最低价在时间次序上的关系,从而无法实现在开仓BAR的止损。因此,必须在记录开仓后最高和最低后,加上Return指令,从而忽略掉后面的止损部分
公式
小学单位换算公式大全免费下载公式下载行测公式大全下载excel公式下载逻辑回归公式下载
。
DMACS_V4主要交易品种测试结果 DMACS_V4主要交易品种测试结果 测试结果(铜) 测试结果(铜) 用30分钟指数图测试,参数进行优化。手续费万分之四,每次操作1手。 测试结果(铜) 测试结果(铜) 用30分钟指数图测试,参数进行优化。手续费万分之四,每次操作1手。 测试结果(胶) 测试结果(胶) 用30分钟指数图测试,参数进行优化。手续费万分之四,每次操作1手。 测试结果(胶) 测试结果(胶) 用30分钟指数图测试,参数进行优化。手续费万分之四,每次操作1手。 测试结果(塑料) 测试结果(塑料) 用30分钟指数图测试,参数进行优化。手续费万分之四,每次操作1手。 测试结果(塑料) 测试结果(塑料) 用30分钟指数图测试,参数进行优化。手续费万分之四,每次操作1手。 测试结果(白糖) 测试结果(白糖) 用30分钟指数图测试,参数进行优化。手续费万分之四,每次操作1手。 测试结果(白糖) 测试结果(白糖) 用30分钟指数图测试,参数进行优化。手续费万分之四,每次操作1手。 实例二:RangeBreak系统 实例二:RangeBreak系统这是个日内交易系统,收盘一定平仓;
RangeBreak基于昨日振幅和今日开盘价的关系。
昨日振幅=昨日最高价-昨日最低价
上轨 = 今日开盘价+N*昨日振幅
下轨 = 今日开盘价-N*昨日振幅
当价格突破上轨,买入开仓。
当价格跌穿下轨,卖出开仓。RangeBreak指标RangeBreak指标Params
Numeric PercentOfRange(0.3);
Vars
Numeric DayOpen;
Numeric preDayRange;
Numeric UpperBand;
Numeric LowerBand;
Begin
DayOpen = OpenD(0);
preDayRange = HighD(1) - LowD(1);
UpperBand = DayOpen + preDayRange*PercentOfRange;
LowerBand = DayOpen - preDayRange*PercentOfRange;
PlotNumeric("UpperBand",UpperBand);
PlotNumeric("LowerBand",LowerBand);
PlotNumeric("MidLine",DayOpen);
EndRangeBreak指标RangeBreak指标RBS_V1(1)RBS_V1(1)Params
Numeric PercentOfRange(0.3);
Numeric ExitOnCloseMins(14.59);
Vars
Numeric DayOpen;
Numeric preDayRange;
Numeric UpperBand;
Numeric LowerBand;
Numeric MyPrice;
Begin
DayOpen = OpenD(0);
preDayRange = HighD(1) - LowD(1);
UpperBand = DayOpen + preDayRange*PercentOfRange;
LowerBand = DayOpen - preDayRange*PercentOfRange;
If(MarketPosition!=1 && High>=UpperBand)
{
MyPrice = UpperBand;
If(Open > MyPrice) MyPrice = Open;
Buy(1,MyPrice);
Return;
} RBS_V1(2)RBS_V1(2) If(MarketPosition!=-1 && Low<=LowerBand)
{
MyPrice = LowerBand;
If(Open < MyPrice) MyPrice = Open;
SellShort(1,MyPrice);
Return;
}
// 收盘平仓
If(Time >=ExitOnCloseMins/100)
{
Sell(1,Open);
BuyToCover(1,Open);
}
SetExitOnClose;
End必须考虑的特殊情况必须考虑的特殊情况如果前一日涨停或跌停,则会出现范围很小。
解决
方案
气瓶 现场处置方案 .pdf气瓶 现场处置方案 .doc见习基地管理方案.doc关于群访事件的化解方案建筑工地扬尘治理专项方案下载
:
设定一个范围的最小值,假定为当前价格的0.2%。代码中的改动代码中的改动Params
Numeric MinRange(0.2);
Vars
NumericSeries DayOpen;
Numeric preDayHigh;
Numeric preDayLow;
NumericSeries preDayRange;
Begin
preDayHigh = HighD(1);
preDayLow = LowD(1);
If(Date!=Date[1])
{
DayOpen = Open;
preDayRange = preDayHigh - preDayLow;
If(preDayRange < Open*MinRange*0.01)
preDayRange = Open*MinRange*0.01;
}Else
{
DayOpen = DayOpen[1];
preDayRange = preDayRange[1];
} 增加止损 增加止损有可能通道会比较宽,难道非要等到反转才平仓?
考虑增加止损设置,有2种方案:
1、亏损固定点数。
2、亏损当前价格的百分比。
考虑到商品价格变化的差异,我们采取第二种方式。止损部分代码止损部分代码 先增加一个变量StopLine,用来保存止损位置。
下面是做多时的止损代码:
If(MarketPosition==1)
{
StopLine = AvgEntryPrice-DayOpen*StopLossSet*0.01;
If(Low <= StopLine)
{
MyPrice = StopLine;
If(Open < MyPrice) MyPrice = Open;
Sell(Lots,MyPrice);
}
}null下面是做空的止损代码:
Else If(MarketPosition==-1)
{
StopLine = AvgEntryPrice+DayOpen*StopLossSet*0.01;
If(High >= StopLine)
{
MyPrice = StopLine;
If(Open > MyPrice) MyPrice = Open;
BuyToCover(Lots,MyPrice);
}
}
入场时间的考虑入场时间的考虑突破的时效性,发生在上午和下午意义是不同的。
不同的商品时效属性不尽相同
为此我们增加最后交易时间参数,可供优化测试来确定最佳值。
实现代码 实现代码增加参数:
Numeric LastTradeMins(14.00);
开仓条件处增加一个时间条件。
If(MarketPosition!=1 && High>=UpperBand && Time < LastTradeMins/100)
{
// 多头开仓
}
If(MarketPosition!=-1 && Low<=LowerBand && Time < LastTradeMins/100)
{
// 空头开仓
}
止赢规则 止赢规则为了防止较大的盈利被吞噬,增加跟踪止赢。
设定跟踪止赢的起始点。
设定跟踪止赢的回撤值。
或者可以选择百分比跟踪止赢。
这里我们采取回撤值。
null要实现跟踪止赢,我们需要记录开仓后出现的最大盈利的位置,即开多仓后出现的最高价,开空仓后出现的最低价。
为了记录最大盈利,我们用两个序列变量,一个记录开仓后的最高价,一个记录开仓后的最低价。 实现代码 实现代码新增变量:
NumericSeries HigherAfterEntry;
NumericSeries LowerAfterEntry;
在脚本开始部分增加以下代码,来记录高低价:
If(BarsSinceEntry == 1)
{
HigherAfterEntry = AvgEntryPrice;
LowerAfterEntry = HigherAfterEntry;
}Else If(BarsSinceEntry > 1)
{
HigherAfterEntry = max(HigherAfterEntry[1],High[1]);
LowerAfterEntry = min(LowerAfterEntry[1],Low[1]);
} null跟踪止损的编码可配合前面的止损编码一起控制。
If(HigherAfterEntry>=AvgEntryPrice+DayOpen*TrailingStart*0.01)
{
StopLine = HigherAfterEntry - DayOpen*TrailingStop*0.01;
}Else // 止损
{
StopLine = AvgEntryPrice-DayOpen*StopLossSet*0.01;
}
If(Low <= StopLine)
{
MyPrice = StopLine;
If(Open < MyPrice) MyPrice = Open;
Sell(1,MyPrice);
}
做空的代码类似。 再进场原则 再进场原则当我们止损或跟踪止损之后,有两种情况我们需要加以控制:
止损后,再次突破上轨或下轨;
追踪止赢后,价格仍符合最初的开仓条件,出场后,马上又会开仓入场。
同时,为了不错失大的波段,我们也需要再次入场,只是进场需要更高的条件。我们增加一条:
再次进场必须在突破前期的高点\低点。 代码的修改 代码的修改我们需要标记止损动作,并要记录高低位。
新建两个布尔型序列变量:
BoolSeries bLongStoped;
BoolSeries bShortStoped;
在脚本开始位置增加处理,保证其值向后传递。
增加HigherAfterEntry和LowerAfterEntry在平仓后的值传递。初次进场和再次进场初次进场和再次进场在原始开仓位置增加条件,开多仓时bLongStoped不能为True,开空仓时bShortStoped不能为True。
在各个交易动作的地方处理这两个序列变量。
增加再次入场的代码:
If(bLongStoped && MarketPosition==0 && High >=UpperBand && High > HigherAfterEntry && Time < LastTradeMins/100)
{
MyPrice = Max(HigherAfterEntry,UpperBand) + MinPoint;
If(Open > MyPrice) MyPrice = Open;
Buy(1,MyPrice);
bLongStoped = False;
Return;
}
null// 做空再次入场代码:
If(bShortStoped && MarketPosition==0 && Low<=LowerBand && Low < LowerAfterEntry && Time < LastTradeMins/100 && bInBoardRange==false)
{
MyPrice = Min(LowerAfterEntry,LowerBand) - MinPoint;
If(Open < MyPrice) MyPrice = Open;
SellShort(1,MyPrice);
bShortStoped = False;
Return;
}
涨跌停的控制涨跌停的控制接近涨跌停板不应开仓。
若有持仓,价格到达涨跌停板马上平仓。判断是否接近涨跌停判断是否接近涨跌停我们新建一个布尔变量bInBoardRange,默认值设置为False。
bInBoardRange =
(Open < Q_LowerLimit + DayOpen*StopLossSet*0.02) Or
( Open > Q_UpperLimit - DayOpen*StopLossSet*0.02);
在开仓条件中加入(bInBoardRange==false)涨跌停板平仓涨跌停板平仓为了在价格达到涨跌停价马上平仓,我们需要在增加如下代码:
做多时:
If(Open == Q_UpperLimit) Sell(1,Open);
做空时:
If(Open == Q_LowerLimit) BuyToCover(Lots,Open);交易次数控制交易次数控制增加失败次数限制,防止单日亏损无限制扩大。
增加二个变量记录失败的次数。
NumericSeries LongFailureCnts;
NumericSeries ShortFailureCnts;
增加一个参数设置最大次数。
Numeric FailureLimit(2);
实现代码实现代码在脚本开始部分增加序列变量值的向后传递处理。
在平仓时增加是否亏损的判断,如果亏损则将计数+1.
If(PositionProfit < 0 ) LongFailureCnts = LongFailureCnts + 1;
在开仓时增加次数限定。
LongFailureCnts < FailureLimit 测试结果(股指) 测试结果(股指) 用1分钟指数图测试,参数未进行优化。手续费每手300元,每次操作1手。 测试结果(天胶) 测试结果(天胶) 用1分钟指数图测试,参数未进行优化。手续费万分之四,每次操作1手。 测试结果(铜) 测试结果(铜) 用1分钟指数图测试,参数未进行优化。手续费万分之四,每次操作1手。 测试结果(铜) 测试结果(铜) 参数优化后,收益曲线更好。谢谢大家!谢谢大家!公司网站:www.tradeblazer.net
新浪微博:weibo.com/tbv4
总部客服: 0755-83410021
上海办事处:021-68366255
我的手机:13501683243
*