分形线的构造
Shashev Sergei | 26 一月, 2016
简介
几乎所有的交易者都会使用分形. 然而, 如果您问他们什么是分形, 他们会给出最好的回答: 它是比尔.威廉姆斯系统的一个指标. 更高级的交易者将会说它是一个五个柱的序列, 其中, 如果中间柱的最高点高于序列中的其他柱, 它就是一个向上分形, 如果中间柱的最低点低于其他柱, 它就是一个向下分形. 正如这句话:“这是我可以讲述的战争”。
分形的简要介绍,特别是它们的性质和用途,在威廉姆斯的命名为"新的交易维度:如何从混乱中股票、债券和商品的利润"的书中有提供。在Chekulaev的叫做"分形(俄文版)"的文章中也可以找到一些内容. 其数学公式在Shiryaev的名为"随机震荡数学基础(俄文版)"中有很好的描述.
使用分形
有两种分形穿透需要注意 - 简单的一种是价格超过了向上分形的水平(或者跌破了向下分形水平). 在这种情况下, 最好是等着看该柱收盘价的状态, 并在下一个柱开启时建立仓位.
对应的买入卖出分形在图上已经使用箭头做标记, 位于简单分形穿透的上方. 一个复杂的穿透使用两个分形 - 最后一个和倒数第二个. 它们连成直线以期待看是否未来有柱的收盘价穿透.
当分形线被穿透时, 进场点使用蓝色和红色箭头标记. MQL4 的开发环境将能帮助我们更好地了解分形.
让我们为测试分形定义一个问题:
- 画出分形买入/卖出
- 画出水平穿透级别;
- 画出分形线;
- 使用箭头标记期待入场点.
分形买入/卖出
这是最基本的部分. 我们也应当考虑MQL4中已有的iFractal指标 (在Omega中, 我必须自己写这个指标, 因为Omega的属性, 这更困难一些). 怎样写这个指标的实例可以在代码库中找到.
穿透的水平级别
让我们使用标准水平线. 我们将把分形的价格作为价格坐标, 形成分形的时间和当前时间将作为时间坐标.
ObjectCreate("SimpleUp"+Up,OBJ_TREND,0,bufUpDate[Up], bufUpPrice[Up],Time[i-1],bufUpPrice[Up]); ObjectSet("SimpleUp"+Up,OBJPROP_COLOR,Aqua); ObjectSet("SimpleUp"+Up,OBJPROP_RAY,True);
分形线
看起来最简单的方法就是通过两个点画出趋势线. 我们做出一条射线然后等待穿透. 但是, 事实上我们没有办法比较收盘价和分形线的价格数值, 因为ObjectGet函数只能取得构成分形线的点的值. 那我们应该怎样做呢?
我们应该记得解析几何学. 我们有两个点, 所以我们就有了一个直线等式. 并且, 因为我们知道时间坐标, 我们可以很容易从直线等式中得到价格值. 标准的直线等式看起来如下:
我们会使用价格和时间替换x和y. 具体的实现在LevelCalcuate中实现, 它计算了穿透水平, 并同时使用ObjectSet函数设置了分形线的新的坐标.
ObjectCreate("LineUp"+Up,OBJ_TREND,0,bufUpDate[Up], bufUpPrice[Up],bufUpDate[Up-1],bufUpPrice[Up-1]); ObjectSet("LineUp"+Up,OBJPROP_COLOR,Blue); ObjectSet("LineUp"+Up,OBJPROP_RAY,False);
放置箭头
我们在循环中构造所需的直线并且把它们与当前价格作比较. 如果它穿透了简单线, 我们就放置一个黄色箭头. 如果它穿透了分形线, 买入的箭头将是蓝色的, 而卖出箭头使用红色.
所有这些都在FractalLines.mq4中实现.
//+------------------------------------------------------------------+ //| FractalLines.mq4 | //| Copyright © 2006, MetaQuotes Software Corp. | //| https://www.metaquotes.net/ | //+------------------------------------------------------------------+ #property copyright "Copyright © 2006, MetaQuotes Software Corp." #property link "https://www.metaquotes.net/" #property indicator_chart_window #property indicator_buffers 2 #property indicator_color1 Blue #property indicator_color2 Red //---- 输入参数 extern int lines=5; //可见分形线的数量 extern int MaxFractals=10000; // :) extern bool ShowHorisontalLines=true; extern bool ShowFractalLines=true; //---- 缓冲区 double ExtMapBuffer1[]; double ExtMapBuffer2[]; //--- 我的变量 double bufUpPrice[10000]; //向上分形的价格数组 double bufUpDate[10000]; //向上分形的日期时间数组 double bufDownPrice[10000]; //向下分形的价格数组 double bufDownDate[10000]; //向下分形的日期时间数组 int Up = 0; //向上分形的计数器 int Down = 0; //向下分形的计数器 //此函数计算分形穿透的价格数值, 计算是根据 //解析几何中的最简等式进行的 double LevelCalculate(double Price1, double Time1, double Price2, double Time2, double NewTime) { double level; if (Time2!=Time1)// 防止被0除. { level=(NewTime-Time1)*(Price2-Price1)/(Time2-Time1)+Price1; } else { return(Price2); } return(level); } //+------------------------------------------------------------------+ //| 自定义指标初始化函数 | //+------------------------------------------------------------------+ int init() { //---- 指标 SetIndexStyle(0,DRAW_ARROW); SetIndexArrow(0,217); SetIndexBuffer(0,ExtMapBuffer1); SetIndexEmptyValue(0,0.0); SetIndexStyle(1,DRAW_ARROW); SetIndexArrow(1,218); SetIndexBuffer(1,ExtMapBuffer2); SetIndexEmptyValue(1,0.0); //---- return(0); } //+------------------------------------------------------------------+ //| 自定义指标去初始化函数 | //+------------------------------------------------------------------+ int deinit() { //---- //---- return(0); } //+------------------------------------------------------------------+ //| 自定义指标迭代函数 | //+------------------------------------------------------------------+ int start() { int counted_bars=IndicatorCounted(); //---- 最后一个计算的柱会被重新计算 if(counted_bars > 0) counted_bars--; int limit = Bars - counted_bars; // 我们将在穿透分形线的时刻放置箭头, // 评估效率 // 此想法是从Rosh那里借来的, 希望他不会反对 :) string arrowName; // 在此我们给箭头一个唯一名称 //被穿透的分形的编号 //穿透了分形线 int FractalUp = 0; int FractalDown = 0; //分形的简单穿透 int SimpleFractalUp = 0; int SimpleFractalDown = 0; double BuyFractalLevel = 0; //穿透向上分形线水平 double SellFractalLevel = 0; //穿透向下分形线水平 double buf = 0; // 出现分形时的缓冲区数值; 如果等于0说明没有分形 //---- 主循环 for(int i = limit; i>0; i--) { //画出简单分形水平 //定义当前分形水平 BuyFractalLevel=LevelCalculate(bufUpPrice[Up],bufUpDate[Up], bufUpPrice[Up-1],bufUpDate[Up-1],Time[i]); //把第二个坐标移动到向上分形线 ObjectSet("LineUp"+Up,OBJPROP_TIME1,Time[i]); ObjectSet("LineUp"+Up,OBJPROP_PRICE1,BuyFractalLevel); SellFractalLevel=LevelCalculate(bufDownPrice[Down], bufDownDate[Down],bufDownPrice[Down-1], bufDownDate[Down-1],Time[i]); //把第二个坐标移动到向下分形线 ObjectSet("LineDown"+Down,OBJPROP_TIME1,Time[i]); ObjectSet("LineDown"+Down,OBJPROP_PRICE1,SellFractalLevel); //搜索简单分形 if (Close[i]>ObjectGet("SimpleUp"+Up,OBJPROP_PRICE1)&& (Up>SimpleFractalUp)) { arrowName="SimleUpArrow"+Up; ObjectCreate(arrowName,OBJ_ARROW,0,Time[i-1], Low[i-1]-Point*10); ObjectSet(arrowName,OBJPROP_ARROWCODE,241); ObjectSet(arrowName,OBJPROP_COLOR,Yellow); SimpleFractalUp=Up; } if (Close[i]<ObjectGet("SimpleDown"+Down,OBJPROP_PRICE1)&& (Down>SimpleFractalDown)) { arrowName="SimleUpArrow"+Down; ObjectCreate(arrowName,OBJ_ARROW,0,Time[i-1], High[i-1]+Point*10); ObjectSet(arrowName,OBJPROP_ARROWCODE,242); ObjectSet(arrowName,OBJPROP_COLOR,Yellow); SimpleFractalDown=Down; } //搜索复杂穿透 if ((Close[i]>BuyFractalLevel)&&(Up>FractalUp)) { //设置向上箭头 arrowName="UpArrow"+Up; ObjectCreate(arrowName,OBJ_ARROW,0,Time[i-1], Low[i-1]-Point*10); ObjectSet(arrowName,OBJPROP_ARROWCODE,241); ObjectSet(arrowName,OBJPROP_COLOR,Blue); FractalUp=Up; } if ((Close[i]<SellFractalLevel)&&(Down>FractalDown)) { //设置向下箭头 arrowName="DownArrow"+Down; ObjectCreate(arrowName,OBJ_ARROW,0,Time[i-1], High[i-1]+Point*10); ObjectSet(arrowName,OBJPROP_ARROWCODE,242); ObjectSet(arrowName,OBJPROP_COLOR,Red); FractalDown=Down; } //画出向上分形自身 ExtMapBuffer1[i] = iFractals(NULL, 0, MODE_UPPER, i); //如果有分形, 把它放进分形数组中 buf = iFractals(NULL, 0, MODE_UPPER, i); if (buf!=0) { Up++; bufUpPrice[Up]=iFractals(NULL, 0, MODE_UPPER, i); bufUpDate[Up]=Time[i]; //当前分形穿透水平 - 分形自身 BuyFractalLevel=bufUpPrice[Up]; if (Up>1) { //简单分形 ObjectCreate("SimpleUp"+Up,OBJ_TREND,0,bufUpDate[Up], bufUpPrice[Up],Time[i-1],bufUpPrice[Up]); ObjectSet("SimpleUp"+Up,OBJPROP_COLOR,Aqua); ObjectSet("SimpleUp"+Up,OBJPROP_RAY,True); //在两个坐标间画出分形线 ObjectCreate("LineUp"+Up,OBJ_TREND,0,bufUpDate[Up], bufUpPrice[Up],bufUpDate[Up-1],bufUpPrice[Up-1]); ObjectSet("LineUp"+Up,OBJPROP_COLOR,Blue); ObjectSet("LineUp"+Up,OBJPROP_RAY,False); //删除旧的线 if (Up>lines+1) { ObjectDelete("LineUp"+(Up-lines)); ObjectDelete("SimpleUp"+(Up-lines)); } } } //类似的代码块, 但是针对向下分形 ExtMapBuffer2[i] = iFractals(NULL, 0, MODE_LOWER, i); buf = iFractals(NULL, 0, MODE_LOWER, i); if (buf!=0) { Down++; bufDownPrice[Down]=iFractals(NULL, 0, MODE_LOWER, i); bufDownDate[Down]=Time[i]; SellFractalLevel=bufDownPrice[Down]; if (Down>1) { ObjectCreate("SimpleDown"+Down,OBJ_TREND,0,bufDownDate[Down], bufDownPrice[Down],Time[i-1],bufDownPrice[Down]); ObjectSet("SimpleDown"+Down,OBJPROP_COLOR,LightCoral); ObjectSet("SimpleDown"+Down,OBJPROP_RAY,True); ObjectCreate("LineDown"+Down,OBJ_TREND,0, bufDownDate[Down],bufDownPrice[Down], bufDownDate[Down-1],bufDownPrice[Down-1]); ObjectSet("LineDown"+Down,OBJPROP_COLOR,Red); ObjectSet("LineDown"+Down,OBJPROP_RAY,False); if (Down>lines+1) { ObjectDelete("LineDown"+(Down-lines)); ObjectDelete("SimpleDown"+(Down-lines)); } } } if (!ShowHorisontalLines) { ObjectDelete("SimpleDown"+Down); ObjectDelete("SimpleUp"+Up); } if (!ShowFractalLines) { ObjectDelete("LineDown"+Down); ObjectDelete("LineUp"+Up); } } //---- return(0); } //+-----------------------------------------------------------------
旧的线必须删除, 否则图表看起来就像个调色板了. 指标还提供了一些额外的设置, 例如线是否可见或者可见线的数量. 指标活动的结果如下所示.
这是为喜欢分形人的特别准备.