布林通道的由来,计算原理,我想不需要再大书这块了,大家百度就可以知道是什么情况。我喜欢布林通道,因为我把它当成移动均线的变种,增加了一个标准偏差值而已,这能在一定程度上反馈交易的心里趋势,增加我们的交易胜算。好了,我这边呢,也不废话了,先来看看它需要的第一个函数VariancePS求估计方差。代码及解释如下:
Params
NumericSeries Price(1);//声明数值型序列参数Price,赋值为1.//
Numeric Length(10);//声明数值型参数Length,赋值10.//
Numeric DataType(1);//声明数值型参数DataType,赋值为1.//
Vars
Numeric Divisor;//声明数值型变量Divisor。//
Numeric SumSqr(0);//声明数值型变量SumSqr,赋值为0.//
Numeric Mean; //声明数值型变量Mean。//
Numeric i;//声明数值型变量i。//
Begin
Divisor = Length-1;//变量Divisor的值等于参数Length减去1.//
If(DataType==1)//假如参数DataType等于1,执行下列语句。//
Divisor = Length;//变量Divisor的值则等于参数Length。//
If(Divisor > 0)//假如变量Divisor的值大于0。//
{
Mean = Average(Price, Length);//变量Mean的值等于10个周期的平均价,前面解释过这个Average求平均函数了。//
for i = 0 to Length - 1//循环的条件,就是从0开始到Length-1结束,就是在这期间的k线反复执行下列的语句。//
{
SumSqr = SumSqr + Sqr( Price[i] - Mean ) ;//又一个累加的语句而已,SumSqr赋值为0,Sqr是一个平方的意思,则Sqr(Price[i] - Mean)等同于(Price[i] - Mean)* (Price[i] - Mean),把这连起来意思就是SumSqr的值逐步累加了。//
}
Return SumSqr / Divisor ;//计算SumSqr总值除以变量Divisor的值,把相除得到的值返回给主函数。//
}Else//假如变量Divisor的值小于等于0,执行下列语句。//
{
Return 0;//返回的是0。//
}
End
好了,我们把方差怎么求的,写好了程序,接下来就可以直接调用它了。接下来就是写如何求标准差函数StandardDev了,代码及解说如下:
Params
NumericSeries Price(1);//声明数值型序列参数Price,赋值为1.//
Numeric Length(10);//声明数值型参数Length,赋值为10.//
Numeric DataType(1);//声明数值型参数DataType,赋值为1.//
Vars
Numeric VarPSValue;//声明数值型变量VarPSValue。//
Begin
VarPSValue = VariancePS(Price, Length, DataType);//变量VarPSValue等于10k线的价格方差。//
If (VarPSValue > 0)//假如变量VarPSValue大于0.//
{
Return Sqrt(VarPSValue);//求得正平方根,如果Sqrt里数字为负,则函数Sqrt返回无效值。这个就是把VarPSValue的平方返回给主函数,即布林通道计算可调用的值。//
}Else//假如VarPSValue小于或等于0的。//
{
Return 0;//返回给主函数就是0了。//
}
End
我们把标准差怎么求的代码也写出来了,接下来布林通道公式调用它的时候就没问题了。下面就是布林通道的代码及解说了:
Params
Numeric Length(20);//声明数值型参数Length,赋值为20.//
Numeric Offset(2); //声明数值型参数Offset,赋值为2.//
Vars
Numeric UpLine; //上轨道,声明它为变量UpLine。//
Numeric DownLine; //下轨道,声明它为变量DownLine。//
NumericSeries MidLine; //中间线,声明它为序列变量MidLine。//
Numeric Band;//声明变量Band。//
Begin
MidLine = AverageFC(Close,Length);//中间线MidLine的值就是求它20个周期的收盘价均值。//
Band = StandardDev(Close,Length,2); //变量Band的值,直接调用StandardDev函数求出来,就是把收盘价,周期及数字2返回去求得。//
UpLine = MidLine + Offset Band;//上轨道 = 20均线的值 + 系数值2 * 标准差。//
DownLine = MidLine - Offset Band; //下轨道 = 20均线的值 - 系数值2 * 标准差。//
PlotNumeric("UpLine",UpLine);//画出上轨道。//
PlotNumeric("DownLine",DownLine);//画出下轨道。//
PlotNumeric("MidLine",MidLine);//画出中间线,即20日均线。//
End
布林通道代码看着简单吧,它的使用方法也简单,就是在突破上下轨道进行买卖,止损就放在中间带上,程序相对简单。交易代码如下:
Params
Numeric Length(20);
Numeric Offset(2);
Vars
NumericSeries UpLine;
NumericSeries DownLine;
NumericSeries MidLine;
Numeric Band;
Begin
MidLine = Average(Close,Length);
Band = StandardDev(Close,Length,2);
UpLine = MidLine + Offset * Band;
DownLine = MidLine - Offset * Band;
PlotNumeric("UpLine",UpLine);
PlotNumeric("DownLine",DownLine);
PlotNumeric("MidLine",MidLine);
If(MarketPosition!=1 && Close[1] > UpLine[1])
{
Buy(1,Open);
}
If(MarketPosition!=-1 && Close[1] < DownLine[1])
{
SellShort(1,Open);
}
If(MarketPosition==1 && Close[1] < MidLine[1])
{
Sell(1,Open);
}
If(MarketPosition==-1 && Close[1] > MidLine[1])
{
BuyToCover(1,Open);
}
End
我们来分析一下,这个系统收益剧烈波多,要是直接用它做程序化交易,恐怕心里都会不自信的,原因在哪呢?按理说,它的预期收益应该不错的,但事实就是如此残酷。我们修改一下,它的开仓条件不变,变的是止损止盈点。我们给个固定止损最小变动的30个点,看结果如何的,记住啊,这个止盈止损点是我习惯性的,你们要是不喜欢这个点数,可以按自己意愿改的。
新代码如下:
Params
Numeric Length(20);
Numeric Offset(2);
Numeric StopPoint(45);
Numeric ProfitPoint(100);
Numeric TrailingStart1(50); // 跟踪止损启动设置1//
Numeric TrailingStart2(80); // 跟踪止损启动设置2//
Numeric TrailingStop1(30); // 跟踪止损设置1//
Numeric TrailingStop2(20); // 跟踪止损设置2//
Numeric StopLossSet(30); //固定止损30个点//
Vars
NumericSeries UpLine;
NumericSeries DownLine;
NumericSeries MidLine;
Numeric Band;
NumericSeries HighestAfterEntry; // 开仓后出现的最高价。//
NumericSeries LowestAfterEntry; //开仓后出现的最低价。//
Numeric MinPoint;
Numeric MyEntryPrice;
Numeric myprice;
Numeric myexitprice;
Begin
MidLine = Average(Close,Length);
Band = StandardDev(Close,Length,2);
UpLine = MidLine + Offset * Band;
DownLine = MidLine - Offset * Band;
PlotNumeric("UpLine",UpLine);
PlotNumeric("DownLine",DownLine);
PlotNumeric("MidLine",MidLine);
If(MarketPosition!=1 && Close[1] > UpLine[1])
{
Buy(1,Open);
}
If(MarketPosition!=-1 && Close[1] < DownLine[1])
{
SellShort(1,Open);
}
If(BarsSinceentry == 0)
{
HighestAfterEntry = Close;
LowestAfterEntry = Close;
If(MarketPosition <> 0)
{
HighestAfterEntry = Max(HighestAfterEntry,AvgEntryPrice); // 开仓的Bar,将开仓价和当时的收盘价的较大值保留到HighestAfterEntry。//
LowestAfterEntry = Min(LowestAfterEntry,AvgEntryPrice); // 开仓的Bar,将开仓价和当时的收盘价的较小值保留到LowestAfterEntry。//
}
}else
{
HighestAfterEntry = Max(HighestAfterEntry,High); // 记录下当前Bar的最高点,用于下一个Bar的跟踪止损判断。//
LowestAfterEntry = Min(LowestAfterEntry,Low); // 记录下当前Bar的最低点,用于下一个Bar的跟踪止损判断。//
}
Commentary("HighestAfterEntry="+Text(HighestAfterEntry));
Commentary("LowestAfterEntry="+Text(LowestAfterEntry));
Commentary("MyEntryPrice="+Text(MyEntryPrice));
MinPoint = MinMove*PriceScale;
MyEntryPrice = AvgEntryPrice;
If(MarketPosition==1) // 有多仓的情况。//
{
If(HighestAfterEntry[1] >= MyEntryPrice + TrailingStart2*MinPoint) // 第二级跟踪止损的条件表达式。//
{
If(Low <= HighestAfterEntry[1] - TrailingStop2*MinPoint)
{
MyExitPrice = HighestAfterEntry[1] - TrailingStop2*MinPoint;
Sell(0,MyExitPrice);
}
}else if(HighestAfterEntry[1] >= MyEntryPrice + TrailingStart1*MinPoint)// 第一级跟踪止损的条件表达式。//
{
If(Low <= HighestAfterEntry[1] - TrailingStop1*MinPoint)
{
MyExitPrice = HighestAfterEntry[1] - TrailingStop1*MinPoint ;
Sell(0,MyExitPrice);
}
}else if(Low <= MyEntryPrice - StopLossSet*MinPoint)//在这里写上固定的止损点。//
{
MyExitPrice = MyEntryPrice - StopLossSet*MinPoint;
Sell(0,MyExitPrice);
}
}else if(MarketPosition==-1) // 有空仓的情况。//
{
If(LowestAfterEntry[1] <= MyEntryPrice - TrailingStart2*MinPoint) // 第二级跟踪止损的条件表达式。//
{
If(High >= LowestAfterEntry[1] + TrailingStop2*MinPoint)
{
MyExitPrice = LowestAfterEntry[1] + TrailingStop2*MinPoint;
BuyToCover(0,MyExitPrice);
}
}else if(LowestAfterEntry[1] <= MyEntryPrice - TrailingStart1*MinPoint)// 第一级跟踪止损的条件表达式。//
{
If(High >= LowestAfterEntry[1] + TrailingStop1*MinPoint)
{
MyExitPrice = LowestAfterEntry[1] + TrailingStop1*MinPoint;
BuyToCover(0,MyExitPrice);
}
}else If(High >= MyEntryPrice + StopLossSet*MinPoint)//在这里写上固定的止损点。//
{
MyExitPrice = MyEntryPrice + StopLossSet*MinPoint;
BuyToCover(0,MyExitPrice);
}
}
End
看到了吧,变好多了,结果是在可接受范围内的,所以说不是这个系统不行,而是我们自己的止损止盈是个很关键的,你进行程序化交易的时候,最怕的就是滑点,所以我还是觉得半自动化的好点,但这总是让我们在操盘时不自觉的按照自己意愿违反程序化,看个人自律吧。