在日语中,“Kagi” 一词表示在发明这种图表的那个年代人们使用的一种 L 形钥匙。同样,这种图还有另一个名称,“钥匙图”。在 Steve Nison 的《日本烛形图技术新解》一书中,您还会看到这种图表的多个别名:价格范围图、钩形图、三角或链形排列图。
这种图有哪些特别之处?它的主要特点在于忽略了时间尺度,仅留下价格尺度(不同于日本的烛形图、柱状图和线形图)。这样,图表将细微的价格浮动隐藏起来,仅显示最明显的价格浮动。
图中展示了一组较粗的阳线和较细的阴线,它们随着市场形势的变化相互交替。市场朝同一方向发展时,线条会延伸到达新的价格范围。但是,如果市场折回并达到预先设定的量,Kagi 线会在新一列中朝相反的方向绘制。这个预先设定的量是以点数(通常用于货币对)或当前价格的百分比数值(通常用于股票)来表示的。线条粗细随距其最近的最高或最低值发生变化。
1. 图表示例
我们以 10 月 8 日到 10 月 11 日 EURUSD,H1 图表的历史数据为例。
图 1 显示的是一幅反向门槛为 15 点的标准图像:
编辑切换为居中
添加图片注释,不超过 140 字(可选)
图 1 Kagi 图,EURUSD H1
我们可以看到,价格从 17:00 开始下跌。下跌趋势一直持续到 21:00。22:00 时,价格从 1.3566 开始上升,最后以 1.3574 收盘。换句话说,价格覆盖了 11 点。这不足以形成逆转,但也没达到新的最低点。之后的两个小时,价格走势平稳,最后在 01:00(10 月 9 日)看到一次强势增长,并以 1.3591 点收盘,增幅达 25 点(1.3591-1.3566)。这意味着价格出现逆转。
这一上升趋势又持续了一个小时。价格达到 1.3599,加强了较粗的阳线。03:00 时,价格急剧下降,以 1.3578 收盘,比之前的最高点低 21 点(1.3599-1.3578)。这足以发生逆转。线条开始向下移动,但形式(粗阳线)没有发生变化。
到 16:00 时,价格下降并最终突破了距离最近的最低值,从粗阳线变为细阴线。之前提到的最低值,即 1.3566,在这里成为突破价。价格继续以阴线的形式移动,并在 10 月 10 日 14:00 变成阳线,突破了距离最近的最高点,也就是 10 月 9 日 23:00 形成的 1.3524。这个小例子展示了 Kagi 图的结构。
2. Kagi 指标制图原则
为了使该指标独立于当前时间表,决定单独复制计划用来形成指标的时间表数据,然后用得到的数据创建指标。
这样便可以在同一图表上同时查看多个时间表,扩大了 Kagi 图的技术分析界限。指标本身位于一个单独的窗口中,但也可以在主图上显示数据。也就是说,指标窗口中显示了基本信息(标准样式或修订样式)。已将指标复制到主图,并绘制出价格和时间标记(取决于设置)。
如前所述,指标绘制出标准版和修订版图表。上面介绍了标准版图表。现在我们来看修订版。
不知道这是不是一种新理念,但我没听说过这样的版本。附加过滤器的理念就是它现在不仅会过滤反转点,还会过滤图表的每一步动作。也就是说价格应移动一定距离以形成新的最高或最低点(不与肩/腰混淆)。一般来说,无论价格走向如何,都应首先移动指定距离。之后再确定它是延续了之前的趋势还是发生了反转。
图 2 显示了这一原则的运作原理。修订后的图表样式显示为蓝色,标准样式显示为红色。我们可以看到,修订后的样式对价格变动的反应较慢,会过滤多数小信号。
编辑切换为居中
添加图片注释,不超过 140 字(可选)
图 2 创建修订版(蓝线)和标准版(红线) Kagi 图
除 Kagi 图外,指标还在指标窗口和主图中提供其它元素。
根据设置,可在指标窗口中设置这些标记。这些标记提供了反转价格数据。也可以用价位实现同样的功能,位于形成指标所用的整个价格范围内或位于每个图表反转点上的各个价位(取决于设置)均匀分布在窗口中。可根据以下三个条件设置颜色:根据反转类型(向上 - 向下)、线条类型(阴 - 阳)或无颜色变化。
主图中提供了反转价格标记,包括临时标记。这些标记(取决于设置)可能为同一颜色,或根据阴阳线的颜色改变颜色。
可利用通过全局变量相互交流的函数实现整个指标代码。
代码可分为三个主要函数和十一个附加函数。基本作图法的主要运算任务和缓冲区填充数据以及附加的缓冲区数组都由指标窗口中 Kagi 图的函数承担。另外两个函数负责提供数据:第一个负责复制时间数据,另一个负责复制选定时间表中每个柱的价格数据。赫兹股票期货量化软件
其它辅助函数负责执行所有作图工作,包括删除对象,卸载指标连同删除所有指标对象,反转参数计算,在主图和指标窗口中绘制标记,创建“走势线”类图形对象,在主图上绘制 Kagi,以及确定新柱的出现以开始形成指标。
3. 指标代码与算法
下面我们仔细了解一下指标代码以及形成该代码的算法。这个代码非常大,新手程序员也许难以理解。通过全局变量相互交流的各个函数使这个代码变得非常混乱。本文将在这一部分分别讲解每个函数以及部分代码。首先,我会介绍指标设置,然后再对复制初始函数的相关数据、反转参数计算、Kagi 图主函数的形成和计算以及其它辅助函数进行说明。
3.1. 指标输入参数
代码从在单独的窗口中声明指标开始,同时声明 12 个缓冲区以及 8 种指标作图法。首先,我们来看为什么选择 8 种作图法,包括两个 “柱状图” 和六个 “线形图”。每个“柱状图”都建立了自己的垂直线。其中一条线负责阴线,另一条负责阳线。
如果存在多条线,则情况会更为复杂,因为每条线都包含三个图形结构。这是因为只要在第一个点附件画出另外一个点,就可以画出一条线。也就是说,我们只需要旋转两个 “线”型图形结构就可以绘制出相互毗邻的两条线。但是,如果我们需要让这些线跳过一些必要的点,就需要第三个图形结构随前两个一起旋转。
图 3 中对此做出了说明,您可以看到使用两个“线”型图形结构的情况:
编辑切换为居中
添加图片注释,不超过 140 字(可选)
图 3 使用两个和三个图形“线”型结构展示肩线与腰线示例
然后,创建设置菜单。这里列举出五项(我们到输入参数中查看这五项)。
第一个输入参数“周期”是形成该结构的周期,随后是 “period_to_redraw” - 图表结构更新周期,最后一个参数是 “start_data” - 时间结构的起点。
这些参数之后是图表结构和其它标签参数:
-
kagi_type – 用户定义的图表结构类型,即标准型或修订型;
-
price_type – 作图使用的价格类型:收盘价、开盘价、最高价、最低价;
-
type_doorstep – 使用的反转类型:点和百分比;
-
doorstep – 反转值(根据上述参数指定点数或百分比数值);
-
color_yin – 指标窗口中的阴线颜色;
-
color_yang – 指标窗口中的阳线颜色;
-
width_yin – 指标窗口中的阴线宽度;
-
width_yang – 指标窗口中的阳线宽度;
-
levels_on_off – 是否应在指标窗口中绘制价格水平;
-
levels_type – 指标窗口中的价格水平类别。有两个数值可供选择:每次反转时或在整个价格范围内均匀分布;
-
levels_number – 指标窗口中的价格水平数目;
-
levels_change_color – 允许更改价格水平线颜色;选项包括高低反转、阴阳线或无变化;
-
levels_first_color – 一个价格水平的第一种颜色;
-
levels_second_color – 一个价格水平的第二种颜色;
-
label_1 – 在指标窗口中绘制图表反转价格标签;
-
label_1_number – 指标窗口中显示的标签数目;
-
label_1_color – 指标窗口中价格标签的颜色;
-
label_2 – 在主图中绘制价格标签;
-
label_2_color – 主图上的标签颜色;
-
time_line_draw – 在主图上绘制反转时间线;
-
time_separate_windows – 绘制主图中反转时间线的延长线;
-
time_line_change_color – 根据阴阳线上的反转标签更改时间线的颜色;
-
time_first_color – 主图上时间线的第一种颜色;
-
time_second_color – 主图上时间线的第二种颜色;
-
kagi_main_chart – 是否需要在主图上绘制 Kagi;
-
color_yin_main – 主图上的阴线颜色;
-
color_yang_main – 主图上的阳线颜色;
-
width_yin_main – 主图上的阴线宽度;
-
width_yang_main – 主图上的阳线宽度;
-
magic_numb – 用于建立并删除对象的幻数以及在指标名称中用于在一个图表中打开多个指标的幻数。
这些参数之后分别声明了指标缓冲区,用于保存价格和时间数值的辅助缓冲区,辅助变量(stop_data、bars_copied、bars_copied_time、copy_history、copy_time),用于将数据保存在图表移动发生变化的阴阳线上的数组,变化发生的时间和价格,以及中心价格(如果在柱上发生阴阳线替换)。最后,声明一个最常用的全局变量,其中包含 “a” 图表移动变化次数数据。
//+------------------------------------------------------------------+ //| BKCV.mq5 | //| Azotskiy Aktiniy ICQ:695710750 | //| https://www.mql5.com/ru/users/Aktiniy | //+------------------------------------------------------------------+ //--- Build Kagi Chart Variable #property copyright "Azotskiy Aktiniy ICQ:695710750" #property link "https://www.mql5.com/en/users/Aktiniy" #property version "1.00" #property description "Build Kagi Chart Variable" #property description " " #property description "This indicator makes drawing a chart Kagi as a matter of indicator window, and in the main chart window" #property indicator_separate_window #property indicator_buffers 12 #property indicator_plots 8 //--- plot Yin #property indicator_label1 "Yin" #property indicator_type1 DRAW_HISTOGRAM2 #property indicator_color1 clrRed #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot Yin1 #property indicator_label2 "Yin1" #property indicator_type2 DRAW_LINE #property indicator_color2 clrRed #property indicator_style2 STYLE_SOLID #property indicator_width2 1 //--- plot Yin2 #property indicator_label3 "Yin2" #property indicator_type3 DRAW_LINE #property indicator_color3 clrRed #property indicator_style3 STYLE_SOLID #property indicator_width3 1 //--- plot Yin3 #property indicator_label4 "Yin3" #property indicator_type4 DRAW_LINE #property indicator_color4 clrRed #property indicator_style4 STYLE_SOLID #property indicator_width4 1 //--- plot Yang #property indicator_label5 "Yang" #property indicator_type5 DRAW_HISTOGRAM2 #property indicator_color5 clrRed #property indicator_style5 STYLE_SOLID #property indicator_width5 2 //--- plot Yang1 #property indicator_label6 "Yang1" #property indicator_type6 DRAW_LINE #property indicator_color6 clrRed #property indicator_style6 STYLE_SOLID #property indicator_width6 2 //--- plot Yang2 #property indicator_label7 "Yang2" #property indicator_type7 DRAW_LINE #property indicator_color7 clrRed #property indicator_style7 STYLE_SOLID #property indicator_width7 2 //--- plot Yang3 #property indicator_label8 "Yang3" #property indicator_type8 DRAW_LINE #property indicator_color8 clrRed #property indicator_style8 STYLE_SOLID #property indicator_width8 2 //--- Enumerations as input data (for more attractive setting) //--- Kagi charting type enum kagi_type_enum { classic=0, // Classic modified=1, // Modified }; //--- Type of the price used for construction enum price_type_enum { c=0, // Close o=1, // Open h=2, // High l=3, // Low }; //--- Type of the used reversal enum type_doorstep_enum { point=0, // Point procent=1, // Percent }; //--- Type of levels location enum levels_type_enum { cor=0, // Cornering equ=1, // Equal distance }; //--- Level colors change type (works when "Type of levels location"="Cornering") enum levels_change_color_enum { up_down=0, // Up & Down yin_yang=1, // Yin & Yang no=2, // Don't change }; //--- input parameters input ENUM_TIMEFRAMES period=PERIOD_CURRENT; // Calculation period to build the chart input ENUM_TIMEFRAMES period_to_redraw=PERIOD_M1; // Refresh period chart input datetime start_data=D'2013.07.10 00:00:00'; // Start time to build the chart input kagi_type_enum kagi_type=classic; // The type to build Kagi chart input price_type_enum price_type=c; // Price used to build chart input type_doorstep_enum type_doorstep=point; // Type calculate doorstep input double doorstep=25; // Doorstep reversal input color color_yin=clrRed; // Color Yin line (indicator window) input color color_yang=clrRed; // Color Yang line (indicator window) input char width_yin=1; // Width Yin line (indicator window) input char width_yang=2; // Width Yang line (indicator window) input bool levels_on_off=false; // Draw level (indicator window) input levels_type_enum levels_type=cor; // Type of drawing levels (indicator window) input uint levels_number=6; // Number of levels (indicator window) input levels_change_color_enum levels_change_color=up_down; // Type change color of levels (indicator window) input color levels_first_color=clrBeige; // The first color of level (indicator window) input color levels_second_color=clrCoral; // The second color of level (indicator window) input bool label_1=true; // Draw price label on (indicator window) input uint label_1_number=10; // The number of labels (indicator window) input color label_1_color=clrGreenYellow; // The color of labels (indicator window) input bool label_2=true; // Draw price label on (main chart) input color label_2_color=clrGreenYellow; // The color of labels (main chart) input bool time_line_draw=true; // Draw a timeline reversal (main chart) input bool time_separate_windows=false; // Draw a timeline reversal on indicator window input bool time_line_change_color=true; // Different color timeline on the Yin and Yang lines (main chart) input color time_first_color=clrRed; // The first color of timeline (main chart) input color time_second_color=clrGreenYellow; // The second color of timeline (main chart) input bool kagi_main_chart=true; // Draw Kagi on main chart (main chart) input color color_yin_main=clrRed; // Color Yin line (main chart) input color color_yang_main=clrRed; // Color Yang line (main chart) input char width_yin_main=1; // Width Yin line (main chart) input char width_yang_main=2; // Width Yang line (main chart) input long magic_numb=65758473787389; // The magic number for drawing objects //--- indicator buffers double YinBuffer1[]; double YinBuffer2[]; double Yin1Buffer[]; double Yin2Buffer[]; double Yin3Buffer[]; double YangBuffer1[]; double YangBuffer2[]; double Yang1Buffer[]; double Yang2Buffer[]; double Yang3Buffer[]; //--- additional variables double Price[]; // Buffer for storing the copied price data double Time[]; // Buffer for storing the copied time data //--- datetime stop_data; // Current time int bars_copied=0; // Number of the already copied bars from the initial date int bars_copied_time; // Number of the already copied bars having the initial date bool copy_history=false; // Price history copying result bool copy_time=false; // Time history copying result //--- datetime time_change[]; // Array for writing the time when the chart movement started changing (up or down) char time_line[]; // Array for storing the data on what line (Yin=0 or Yang=1) direction has changed double time_change_price[]; // Array for writing the chart movement change price double time_central_price[]; // Array for writing the average price during the chart movement change uint a=0; // Variable for building the chart, number of chart reversals is fixed
3.2. 指标初始化函数
下一个是指标初始化函数。这里对指标缓冲区及其索引(主要作为时间序列;Kagi 图比主图要短,因此最好可以向后画)做出说明。同时还要设置不在屏幕上显示哪些数值(EMPTY_VALUE=-1)。
现在我们来分配指标名称和设定显示精度。如前所述,名称中加入了幻数。这样做是为了正确运算 ChartWindowFind() 函数。否则,在指标窗口中绘出的图形对象会只在首次打开的指标中显示(如果在同一图表中使用多个指标)。
接下来,我们指定作图线名称,禁止在指标窗口中显示当前数值,设置阴阳线的颜色和宽度,设置在指标窗口中显示几个价格水平。
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,YinBuffer1,INDICATOR_DATA); ArraySetAsSeries(YinBuffer1,true); SetIndexBuffer(1,YinBuffer2,INDICATOR_DATA); ArraySetAsSeries(YinBuffer2,true); SetIndexBuffer(2,Yin1Buffer,INDICATOR_DATA); ArraySetAsSeries(Yin1Buffer,true); SetIndexBuffer(3,Yin2Buffer,INDICATOR_DATA); ArraySetAsSeries(Yin2Buffer,true); SetIndexBuffer(4,Yin3Buffer,INDICATOR_DATA); ArraySetAsSeries(Yin3Buffer,true); //--- SetIndexBuffer(5,YangBuffer1,INDICATOR_DATA); ArraySetAsSeries(YangBuffer1,true); SetIndexBuffer(6,YangBuffer2,INDICATOR_DATA); ArraySetAsSeries(YangBuffer2,true); SetIndexBuffer(7,Yang1Buffer,INDICATOR_DATA); ArraySetAsSeries(Yang1Buffer,true); SetIndexBuffer(8,Yang2Buffer,INDICATOR_DATA); ArraySetAsSeries(Yang2Buffer,true); SetIndexBuffer(9,Yang3Buffer,INDICATOR_DATA); ArraySetAsSeries(Yang3Buffer,true); //--- add the buffer for copying data on prices for calculation SetIndexBuffer(10,Price,INDICATOR_CALCULATIONS); //--- add the buffer for copying data on bar open time for construction SetIndexBuffer(11,Time,INDICATOR_CALCULATIONS); //--- set what values are not to be drawn for(char x=0; x<8; x++) { PlotIndexSetDouble(x,PLOT_EMPTY_VALUE,-1); } //--- set the indicator's look IndicatorSetString(INDICATOR_SHORTNAME,"BKCV "+IntegerToString(magic_numb)); // Indicator name IndicatorSetInteger(INDICATOR_DIGITS,_Digits); // Display accuracy //--- assign names to graphical constructions PlotIndexSetString(0,PLOT_LABEL,"Yin"); PlotIndexSetString(1,PLOT_LABEL,"Yin"); PlotIndexSetString(2,PLOT_LABEL,"Yin"); PlotIndexSetString(3,PLOT_LABEL,"Yin"); PlotIndexSetString(4,PLOT_LABEL,"Yang"); PlotIndexSetString(5,PLOT_LABEL,"Yang"); PlotIndexSetString(6,PLOT_LABEL,"Yang"); PlotIndexSetString(7,PLOT_LABEL,"Yang"); //--- prohibit display of the results of the current values for graphical constructions PlotIndexSetInteger(0,PLOT_SHOW_DATA,false); PlotIndexSetInteger(1,PLOT_SHOW_DATA,false); PlotIndexSetInteger(2,PLOT_SHOW_DATA,false); PlotIndexSetInteger(3,PLOT_SHOW_DATA,false); PlotIndexSetInteger(4,PLOT_SHOW_DATA,false); PlotIndexSetInteger(5,PLOT_SHOW_DATA,false); PlotIndexSetInteger(6,PLOT_SHOW_DATA,false); PlotIndexSetInteger(7,PLOT_SHOW_DATA,false); //--- set color for Yin line PlotIndexSetInteger(0,PLOT_LINE_COLOR,color_yin); PlotIndexSetInteger(1,PLOT_LINE_COLOR,color_yin); PlotIndexSetInteger(2,PLOT_LINE_COLOR,color_yin); PlotIndexSetInteger(3,PLOT_LINE_COLOR,color_yin); //--- set color for Yang line PlotIndexSetInteger(4,PLOT_LINE_COLOR,color_yang); PlotIndexSetInteger(5,PLOT_LINE_COLOR,color_yang); PlotIndexSetInteger(6,PLOT_LINE_COLOR,color_yang); PlotIndexSetInteger(7,PLOT_LINE_COLOR,color_yang); //--- set Yin line width PlotIndexSetInteger(0,PLOT_LINE_WIDTH,width_yin); PlotIndexSetInteger(1,PLOT_LINE_WIDTH,width_yin); PlotIndexSetInteger(2,PLOT_LINE_WIDTH,width_yin); PlotIndexSetInteger(3,PLOT_LINE_WIDTH,width_yin); //--- set Yang line width PlotIndexSetInteger(4,PLOT_LINE_WIDTH,width_yang); PlotIndexSetInteger(5,PLOT_LINE_WIDTH,width_yang); PlotIndexSetInteger(6,PLOT_LINE_WIDTH,width_yang); PlotIndexSetInteger(7,PLOT_LINE_WIDTH,width_yang); //--- set the number of levels in the indicator window IndicatorSetInteger(INDICATOR_LEVELS,levels_number); //--- return(INIT_SUCCEEDED); }
3.3. 数据复制函数
现在我们来看数据复制函数。
这里有两个数据复制函数。第一个用来复制价格,第二个用来复制每个柱的开盘时间。两个函数都将其数值保存在之前声明的指标的计算缓冲区中。
首先,我们看价格复制函数。函数输入参数:用户保存数据的数组、数据复制起始时间(当前时间)。该函数体包含用于该函数的相应变量,复制到中间数组的数据量(柱),中间动态数组本身,以及应复制到中间数组的柱的数目。要根据既定时间内总的柱数以及在上一次调用函数时复制的柱数(全局变量)来计算柱的数目。
如果这不是第一次复制数据,则应更新上一次复制的柱上的数据。这时需要用以往复制的柱数减一,并用新复制的柱数加一。我们还要改变中间数组的大小,从而为复制柱做好准备。
根据设置,我们会将价格复制到中间数组。复制成功后,数据会从中间数组被复制到缓冲区数组(函数响应数组)的最后,对函数赋予正数答案并更新存有已复制柱数数据的全局变量。这类复制只允许复制减去复制时间后的几个柱。
//+------------------------------------------------------------------+ //| Func Copy History | //+------------------------------------------------------------------+ bool func_copy_history(double &result_array[], datetime data_start, datetime data_stop) { //--- int x=false; // Variable for answer int result_copy=-1; // Number of copied data static double price_interim[]; // Temporary dynamic array for storing copied data static int bars_to_copy; // Number of bars for copying bars_to_copy=Bars(_Symbol,period,data_start,data_stop); // Find out the current number of bars on the time interval bars_to_copy-=bars_copied; // Calculate the number of bars to be copied if(bars_copied!=0) // If it is not the first time the data has been copied { bars_copied--; bars_to_copy++; } ArrayResize(price_interim,bars_to_copy); // Change the size of the receiving array switch(price_type) { case 0: result_copy=CopyClose(_Symbol,period,0,bars_to_copy,price_interim); break; case 1: result_copy=CopyOpen(_Symbol,period,0,bars_to_copy,price_interim); break; case 2: result_copy=CopyHigh(_Symbol,period,0,bars_to_copy,price_interim); break; case 3: result_copy=CopyLow(_Symbol,period,0,bars_to_copy,price_interim); break; } if(result_copy!=-1) // If copying to the intermediate array is successful { ArrayCopy(result_array,price_interim,bars_copied,0,WHOLE_ARRAY); // Copy the data from the temporary array to the main one x=true; // assign the positive answer to the function bars_copied+=result_copy; // Increase the value of the processed data } //--- return(x); }
下一个函数用来复制时间数据。与上一个函数不同,它用来处理另一种变量 - 日期时间(当复制到时间缓冲区数组 - 函数答案数组时,该变量会转换为双变量)。另一个不同之处就是这个函数没有使用 switch() 语句,因为它无需选择已经复制的数据。赫兹股票期货量化软件
//+------------------------------------------------------------------+ //| Func Copy Time | //+------------------------------------------------------------------+ bool func_copy_time(double &result_array[], datetime data_start, datetime data_stop) { //--- int x=false; // Variable for answer int result_copy=-1; // Number of copied data static datetime time_interim[]; // Temporary dynamic array for storing copied data static int bars_to_copy_time; // Number of bars for copying bars_to_copy_time=Bars(_Symbol,period,data_start,data_stop); // Find out the current number of bars on the time interval bars_to_copy_time-=bars_copied_time; // Calculate the number of bars to be copied if(bars_copied_time!=0) // If it is not the first time the data has been copied { bars_copied_time--; bars_to_copy_time++; } ArrayResize(time_interim,bars_to_copy_time); // Change the size of the receiving array result_copy=CopyTime(_Symbol,period,0,bars_to_copy_time,time_interim); if(result_copy!=-1) // If copying to the intermediate array is successful { ArrayCopy(result_array,time_interim,bars_copied_time,0,WHOLE_ARRAY); // Copy the data from the temporary array to the main one x=true; // assign the positive answer to the function bars_copied_time+=result_copy; // Increase the value of the processed data } //--- return(x); }
3.4. 反转参数计算函数
由于反转参数可能是点数,也可能是百分比,因此我们需要函数能够根据指标设置计算反转参数。这个函数只有一个参数(价格)用于计算百分比反转参数。这个答案的变量会首先通过 double 型进行初始化,经过计算,它会被间接转化为 int 型以响应函数。
这样做是由于在计算中使用了浮点数,而答案应以整数形式呈现。函数中通过 if-else 条件语句实现了选择。直接与外部 input 变量(指标参数)进行比较。并用线性方程计算点数。首先,确定价格覆盖的总点数。然后,根据这一数字计算具体百分比,并用得到的百分比数据给返回变量赋值。
//+------------------------------------------------------------------+ //| Func Calculate Doorstep | //+------------------------------------------------------------------+ int func_calc_dorstep(double price) { double x=0; // Variable for answer if(type_doorstep==0) // If the calculation is to be performed in points { x=doorstep; } if(type_doorstep==1) // If the calculation is to be performed in percentage { x=price/_Point*doorstep/100; } return((int)x); }
3.5. 主函数 - 绘制 Kagi 图
我们已经检查了主函数运算所需的所有函数 - 在指标窗口中绘制 Kagi 图(即,填充指标缓冲区)。函数的输入参数由数据数组构成。其中两个为以上所说的计算缓冲区(之前赋值的价格与时间),其余都是指标作图缓冲区的数组。赫兹股票期货量化软件
函数中声明了作图时用于保存数据的必要变量。由于作图时使用 for 循环语句,我们需要获得上次计算结束阶段的数据。这可以通过六个变量获得:line_move - 上次计算时发生价格变动的位置,line_gauge - 阴阳线粗细(宽度),price_1 and price_2 - 正在考虑的以往价格与当前价格,price_down and price_up - 之前的肩价和腰价。 我们可以看到,由于在循环的最开始,尚未进行比较之前的计算中便已经包含了 price_1 变量,因此这个变量会被立即等同于已复制的价格数组的第一个元素。
由于指标作图的缓冲区数组拥有 AS_SERIES 索引标记,需要以相反顺序填写这些数组。因此要实现大小合适的时间数组。然后以同样方式转换用于保存时间数据、线条类型、肩与腰,以及反转价格的全局变量。
然后应以“空”值(-1)填写所有数组。使用两个小循环即可完成这一步。也可以在单个循环中加入所有数组。但使用两个循环会让每步动作更清晰,执行时间也不会发生多大变化。也就是说,分别单独填写图形缓冲区和计算时间缓冲区。
现在,已声明、转换并填写所有变量,可以开始启动主循环。主循环非常大(尽管计算速度足够快),且包括扫描之前复制的所有柱。
循环会通过已经复制的所有柱,并填写之前声称的所有必要数组,从而进一步与其合作。首先,我们来定义循环中使用的所有数组:赫兹股票期货量化软件
-
yin_int_1 - 垂直阴线价格的第一个数值(如果绘制出垂直阴线,且图表走势向下,这就是价格的上限值;如果图表走势向上,这就是价格的下限值);
-
yin_int_2 - 垂直阴线价格的第二个数值(如果线条走势向上,这就是上限值;如果线条走势向下,这就是下限值);
-
yang_int_1 - 垂直阳线价格的第一个数值;
-
yang_int_2 - 垂直阳线价格的第二个数值;
-
lin_yin - 水平阴线值(阴线上的反转价格);
-
lin_yang - 水平阳线值(阳线上的反转价格);
-
time_change - 图表反转时间(形成肩或腰);
-
time_line - 阴 = 0 或阳 = 1 反转期间的线条;
-
time_central_price - 中心价格的数值,中心价格即阴线转换为阳线或阳线转换为阴线时的价格;
-
time_change_price - 反转(肩或腰)价格数值,这是一个公用变量,不随阴阳线的类型发生变化。
在每次循环开始前用当前分析的来自价格缓冲区的价格数值给 price_2 变量赋值,从而在 if-else 条件语句中做出进一步对比。之后,将逐步分析已经复制的数据的缓冲区数组,并填写上述数组。每个 if-else 条件语句都会根据条件执行某些操作,这些条件包括:图表线条之前的方向(上或下)以及线条之前的形式(阴或阳)。然后根据作图类型(标准或修订)检查移动条件(价格是否通过了某个数目的点)。赫兹股票期货量化软件
满足各项条件后,会重新给变量赋值或确定变量(数组元素)。最开始便确定了线条类型(阴还是阳)。根据移动和之前的操作来进行下一步分布。
存在两种可能的价格变动;
-
价格上升;
-
价格下降。
每个方向还包含四类之前的操作:
-
上一条线是阴线,趋势向上;
-
上一条线是阳线,趋势向上;
-
上一条线是阴线,趋势向下;
-
上一条线是阳线,趋势向下;
这样,在图表最初运动(出现第一条线)的前两个定义中,我们便分为八种情况。赫兹股票期货量化软件
之后,主循环结束。要在较小的循环中建立图表需要为缓冲区重新赋值(反转)并进行填充,这个较小的循环包括之前在主循环中定义,并被写入 “a” 变量的 Kagi 图的反转次数。至于分布最高价和最低价数值以及垂直线,则非常简单:执行一次简单的反转。也就是说,之前获得的主要数值(拥有 0、1、2、3...指数的数组)已被分配到缓冲区的最终值(将具有 “a” 索引(即 a、a-1、a-2、a-3...)的元素用作最终数值)。为防止反转(水平)线相互纠缠在一起,按上文所述用 switch 语句进行旋转。赫兹股票期货量化软件
这样,便完成了 Kagi 作图的主函数。赫兹股票期货量化软件
//+------------------------------------------------------------------+ //| Func Draw Kagi | //+------------------------------------------------------------------+ void func_draw_kagi(double &array_input[], double &arr_yin_1[], double &arr_yin_2[], double &arr_yin_lin1[], double &arr_yin_lin2[], double &arr_yin_lin3[], double &arr_yang_1[], double &arr_yang_2[], double &arr_yang_lin1[], double &arr_yang_lin2[], double &arr_yang_lin3[], double &arr_time[]) { //--- a=0; // Variable for the chart construction fixing the number of chart reversals char line_move=0; // Previous price direction 1-up, -1-down char line_gauge=0; // Previous look of the line 1-thick yang, -1-thin yin double price_1=0,price_2=0; // Auxiliary variables for defining the price movement double price_down=-99999,price_up=99999; // Auxiliary variables for storing the reversal price values price_1=array_input[0]; //--- auxiliary arrays for the initial data storing before the reversal (transferring to the buffers) double yin_int_1[]; double yin_int_2[]; double lin_yin[]; double yang_int_1[]; double yang_int_2[]; double lin_yang[]; //--- change the sizes of dynamic arrays ArrayResize(yin_int_1,bars_copied); ArrayResize(yin_int_2,bars_copied); ArrayResize(yang_int_1,bars_copied); ArrayResize(yang_int_2,bars_copied); ArrayResize(lin_yin,bars_copied); ArrayResize(lin_yang,bars_copied); //--- time data storing arrays ArrayResize(time_change,bars_copied_time); ArrayResize(time_line,bars_copied_time); // Look of the line Yin = 0 or Yang = 1 ArrayResize(time_change_price,bars_copied_time); ArrayResize(time_central_price,bars_copied_time); //--- assign -1 (not displayed) value to the transferred buffers for(int z=0; z<bars_copied; z++) { arr_yin_1[z]=-1; arr_yin_2[z]=-1; arr_yin_lin1[z]=-1; arr_yin_lin2[z]=-1; arr_yin_lin3[z]=-1; arr_yang_1[z]=-1; arr_yang_2[z]=-1; arr_yang_lin1[z]=-1; arr_yang_lin2[z]=-1; arr_yang_lin3[z]=-1; } //--- equate -1 (not displayed) value to the arrays for(int z=0; z<bars_copied; z++) { yin_int_1[z]=-1; yin_int_2[z]=-1; lin_yin[z]=-1; yang_int_1[z]=-1; yang_int_2[z]=-1; lin_yang[z]=-1; time_change[z]=-1; time_line[z]=-1; time_change_price[z]=-1; time_central_price[z]=-1; } //--- function's main loop for(int z=0; z<bars_copied; z++) { price_2=array_input[z]; //--- first, let's define the initial market direction //--- first THIN DESCENDING line if(((price_1-price_2)/_Point>func_calc_dorstep(price_2)) && line_move==0) { yin_int_1[a]=price_1; yin_int_2[a]=price_2; line_move=-1; line_gauge=-1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=0; } //--- first THICK ASCENDING line if(((price_1-price_2)/_Point<-func_calc_dorstep(price_2)) && line_move==0) { yang_int_1[a]=price_1; yang_int_2[a]=price_2; line_move=1; line_gauge=1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=1; } //--- price moves DOWN //--- if the price moved DOWN before that, the line is THIN if(line_move==-1 && line_gauge==-1) { if(((price_1-price_2)/_Point>func_calc_dorstep(price_2)) || (kagi_type==0 && (price_1-price_2)/_Point>0)) { yin_int_2[a]=price_2; line_move=-1; line_gauge=-1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=0; } } //--- if the price moved DOWN before that, the line is THICK if(line_move==-1 && line_gauge==1) { if(((price_1-price_2)/_Point>func_calc_dorstep(price_2)) || (kagi_type==0 && (price_1-price_2)/_Point>0)) { if(price_2<price_down) // If the thick line crossed the lower shoulder when moving downwards { yin_int_1[a]=price_down; yin_int_2[a]=price_2; yang_int_2[a]=price_down; line_move=-1; line_gauge=-1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_central_price[a]=price_down; time_line[a]=0; } else //if(price_2>=price_down) // If the thick line has not crossed the lower shoulder when moving downwards { yang_int_2[a]=price_2; line_move=-1; line_gauge=1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=1; } } } //--- if the price has moved UPWARDS before that, the line is THIN if(line_move==1 && line_gauge==-1) { if((price_1-price_2)/_Point>func_calc_dorstep(price_2)) { a++; yin_int_1[a]=price_1; yin_int_2[a]=price_2; lin_yin[a]=price_1; line_move=-1; line_gauge=-1; price_up=price_1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=0; time_change_price[a]=lin_yin[a]; } } //--- if the price has moved UPWARDS before that, the line is THICK if(line_move==1 && line_gauge==1) { if((price_1-price_2)/_Point>func_calc_dorstep(price_2)) { a++; if(price_2<price_down) // If the thick line has crossed the lower shoulder when moving downwards { yin_int_1[a]=price_down; yin_int_2[a]=price_2; yang_int_1[a]=price_1; yang_int_2[a]=price_down; lin_yang[a]=price_1; line_move=-1; line_gauge=-1; price_up=price_1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=0; time_change_price[a]=lin_yang[a]; time_central_price[a]=price_down; } else//if(price_2>=price_down) // If the thick line has not crossed the lower shoulder when moving downwards { yang_int_1[a]=price_1; yang_int_2[a]=price_2; lin_yang[a]=price_1; line_move=-1; line_gauge=1; price_up=price_1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=1; time_change_price[a]=lin_yang[a]; } } } //--- the price moves UP //--- if the price has moved UPWARDS before that, the line is THICK if(line_move==1 && line_gauge==1) { if(((price_1-price_2)/_Point<-func_calc_dorstep(price_2)) || (kagi_type==0 && (price_1-price_2)/_Point<0)) { yang_int_2[a]=price_2; line_move=1; line_gauge=1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=1; } } //--- if the price has moved UPWARDS before that, the line is THIN if(line_move==1 && line_gauge==-1) { if(((price_1-price_2)/_Point<-func_calc_dorstep(price_2)) || (kagi_type==0 && (price_1-price_2)/_Point<0)) { if(price_2>price_up) // If the thin line has not crossed the upper shoulder when moving upwards { yin_int_2[a]=price_up; yang_int_1[a]=price_up; yang_int_2[a]=price_2; line_move=1; line_gauge=1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_central_price[a]=price_up; time_line[a]=1; } else//if(price_2<=price_up) // If the thin line has not crossed the upper shoulder when moving upwards { yin_int_2[a]=price_2; line_move=1; line_gauge=-1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=0; } } } //--- if the price has moved DOWNWARDS before that, the line is THICK if(line_move==-1 && line_gauge==1) { if((price_1-price_2)/_Point<-func_calc_dorstep(price_2)) { a++; yang_int_1[a]=price_1; yang_int_2[a]=price_2; lin_yang[a]=price_1; line_move=1; line_gauge=1; price_down=price_1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=1; time_change_price[a]=lin_yang[a]; } } //--- if the price has moved DOWNWARDS before that, the line is THIN if(line_move==-1 && line_gauge==-1) { if((price_1-price_2)/_Point<-func_calc_dorstep(price_2)) { a++; if(price_2>price_up) // If the thin line has crossed the upper shoulder when moving upwards { yin_int_1[a]=price_1; yin_int_2[a]=price_up; yang_int_1[a]=price_up; yang_int_2[a]=price_2; lin_yin[a]=price_1; line_move=1; line_gauge=1; price_down=price_1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=1; time_change_price[a]=lin_yin[a]; time_central_price[a]=price_up; } else //if(price_2<=price_up) // If the thin line has not crossed the upper shoulder when moving upwards { yin_int_1[a]=price_1; yin_int_2[a]=price_2; lin_yin[a]=price_1; line_move=1; line_gauge=-1; price_down=price_1; price_1=price_2; time_change[a]=(datetime)arr_time[z]; time_line[a]=0; time_change_price[a]=lin_yin[a]; } } } } //--- function's main loop //--- assign actual values to drawing buffers uint y=a; //--- auxiliary variables for storing data on filling the current buffer char yin=1; char yang=1; for(uint z=0; z<=a; z++) { arr_yin_1[z]=yin_int_1[y]; arr_yin_2[z]=yin_int_2[y]; switch(yin) { case 1: { arr_yin_lin1[z]=lin_yin[y]; arr_yin_lin1[z+1]=lin_yin[y]; yin++; } break; case 2: { arr_yin_lin2[z]=lin_yin[y]; arr_yin_lin2[z+1]=lin_yin[y]; yin++; } break; case 3: { arr_yin_lin3[z]=lin_yin[y]; arr_yin_lin3[z+1]=lin_yin[y]; yin=1; } break; } arr_yang_1[z]=yang_int_1[y]; arr_yang_2[z]=yang_int_2[y]; switch(yang) { case 1: { arr_yang_lin1[z]=lin_yang[y]; arr_yang_lin1[z+1]=lin_yang[y]; yang++; } break; case 2: { arr_yang_lin2[z]=lin_yang[y]; arr_yang_lin2[z+1]=lin_yang[y]; yang++; } break; case 3: { arr_yang_lin3[z]=lin_yang[y]; arr_yang_lin3[z+1]=lin_yang[y]; yang=1; } break; } y--; } //--- }