第六章 数组函数
在MQL5语言中,数组的最大维数为四维。每个维度的索引编号都是从0到dimension_size - 1。在一个特定例子中,如一个由50个元素组成的一维数组,在调用时,第一个元素的索引编号为 [0]
,最后一个数组的元素索引为 [49]
。
函数 | 功能 |
ArrayBsearch | 返回在一维数组中的找到的第一个元素的索引编号 |
ArrayCopy | 复制一个数组到另一个数组中 |
ArrayFree | 释放任何动态数组的缓冲区,并将0维度的大小设置为0 |
ArrayCompare | 返回比较 两组简单类型的数组 或 没有复杂对象的自定义结构 的结果 |
ArrayGetAsSeries | 检查数组索引的方向 |
ArrayInitialize | 将数字数组的所有元素设置为单个值 |
ArrayFill | 用指定的值填充数组 |
ArrayIsSeries | 检查数组是否为一个时间序列 |
ArrayIsDynamic | 检测是否数组是否动态的 |
ArrayMaximum | 检测元素的最大值 |
ArrayPrint | 将 简单类型 或 简单结构 的数组打印输出到日志 |
ArrayMinimum | 检测元素的最小值 |
ArrayRange | 返回数组中指定维度中的元素个数。 |
ArrayResize | 为数组的第一个维度设置新的大小 |
ArraySetAsSeries | 设置数组索引编号的方向 |
ArraySize | 返回数组中元素的数量 |
ArraySort | 通过第一个维度对数字数组进行排序 |
ArraySwap | 交换相同类型两个动态数组的内容 |
# 6.1 ArrayBsearch
在 升序排列 的多维数值数组中搜索指定的值。搜索是通过第一个维度的元素执行的。
搜寻双精度数组
int ArrayBsearch(
const double& array[], // 用来搜索的数组
double value // 搜索什么
);
2
3
4
搜寻浮点型数组
int ArrayBsearch(
const float& array[], // 用来搜索的数组
float value // 搜索什么
);
2
3
4
搜寻长整型数组
int ArrayBsearch(
const long& array[], // 用来搜索的数组
long value // 搜索什么
);
2
3
4
搜寻整型数组
int ArrayBsearch(
const int& array[], // 用来搜索的数组
int value // 搜索什么
);
2
3
4
搜寻短整型数组
int ArrayBsearch(
const short& array[], // 用来搜索的数组
short value // 搜索什么
);
2
3
4
搜寻字符型数组
int ArrayBsearch(
const char& array[], // 用来搜索的数组
char value // 搜索什么
);
2
3
4
参数
array[]
[in] 用来搜索的数组
value
[in] 搜寻值
返回值
函数返回已找到元素的索引编号。如果没有找到所需的值,函数将返回一个最接近搜寻值的元素的索引编号。
注意
二进制搜索的过程只对排序过的数组进行。排序数组可以使用ArraySort()函数。
示例:
#property description "Script based on RSI indicator data displays"
#property description "how often the market was in"
#property description "overbought and oversold areas in the specified time interval."
// 基于RSI指标数据的脚本显示了在指定的时间间隔内,市场在超买和超卖区域的频率。
//--- 启动脚本时显示输入参数的窗口
#property script_show_inputs
//--- 输入参数
input int InpMAPeriod=14; // 移动平均周期
input ENUM_APPLIED_PRICE InpAppliedPrice=PRICE_CLOSE; // 价格类型
input double InpOversoldValue=30.0; // 超卖水平线
input double InpOverboughtValue=70.0; // 超买水平线
input datetime InpDateStart=D'2012.01.01 00:00'; // 分析开始日期
input datetime InpDateFinish=D'2013.01.01 00:00'; // 分析结束日期
//+------------------------------------------------------------------+
//| 脚本程序开始函数 |
//+------------------------------------------------------------------+
void OnStart()
{
double rsi_buff[]; // 指标值的数组
int size=0; // 数组大小
//--- 接收RSI指标处理
ResetLastError();
int rsi_handle=iRSI(Symbol(),Period(),InpMAPeriod,InpAppliedPrice);
if(rsi_handle==INVALID_HANDLE)
{
//--- 接收指标处理失败
PrintFormat("指标处理接收错误。错误代码 = %d",GetLastError());
return;
}
//--- 循环中,直到指标计算它的所有值
while(BarsCalculated(rsi_handle)==-1)
{
//--- 如果指标强制完成脚本操作则退出
if(IsStopped())
return;
//--- 暂停允许指标计算它的所有值
Sleep(10);
}
//--- 复制一段时间的指标值
ResetLastError();
if(CopyBuffer(rsi_handle,0,InpDateStart,InpDateFinish,rsi_buff)==-1)
{
PrintFormat("未能复制指标值。错误代码 = %d",GetLastError());
return;
}
//--- 接收数组大小
size=ArraySize(rsi_buff);
//--- 分类数组
ArraySort(rsi_buff);
//--- 找出市场在超卖区域的时间(百分比)
double ovs=(double)ArrayBsearch(rsi_buff,InpOversoldValue)*100/(double)size;
//--- 找出市场在超买区域的时间(百分比)
double ovb=(double)(size-ArrayBsearch(rsi_buff,InpOverboughtValue))*100/(double)size;
//--- 显示数据的字符串形式
string str="从 "+TimeToString(InpDateStart,TIME_DATE)+" 到 "
+TimeToString(InpDateFinish,TIME_DATE)+" 市场价格在:";
string str_ovb="在超买区域 "+DoubleToString(ovb,2)+"% 总时长";
string str_ovs="在超卖区域 "+DoubleToString(ovs,2)+"% 总时长";
//--- 在图表上显示数据
CreateLabel("顶",5,60,str,clrDodgerBlue);
CreateLabel("超买",5,35,str_ovb,clrDodgerBlue);
CreateLabel("超卖",5,10,str_ovs,clrDodgerBlue);
//--- 重绘图表
ChartRedraw(0);
//--- 暂停
Sleep(10000);
}
//+------------------------------------------------------------------+
//| 在图表左下角显示文本 |
//+------------------------------------------------------------------+
void CreateLabel(const string name,const int x,const int y,
const string str,const color clr)
{
//--- 创建一个标签
ObjectCreate(0,name,OBJ_LABEL,0,0,0);
//--- 绑定标签到左下角
ObjectSetInteger(0,name,OBJPROP_CORNER,CORNER_LEFT_LOWER);
//--- 改变定位点位置
ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_LEFT_LOWER);
//--- X方向定位点的距离
ObjectSetInteger(0,name,OBJPROP_XDISTANCE,x);
//--- Y方向定位点的距离
ObjectSetInteger(0,name,OBJPROP_YDISTANCE,y);
//--- 标签文本
ObjectSetString(0,name,OBJPROP_TEXT,str);
//--- 文本颜色
ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
//--- 文本大小
ObjectSetInteger(0,name,OBJPROP_FONTSIZE,12);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# 6.2 ArrayCopy
复制一个数组到另一个数组中。
int ArrayCopy(
void& dst_array[], // 目标数组
const void& src_array[], // 源数组
int dst_start=0, // 写入目标数组的索引编号
int src_start=0, // 源数组的最初索引编号
int count=WHOLE_ARRAY // 元素数量
);
2
3
4
5
6
7
参量
dst_array[]
[out] 目标 数组
src_array[]
[in] 源 数组
dst_start=0
[in] 从目标数组的第几个元素开始写入,默认为0 。
src_start=0
[in] 从源数组的第几个元素开始读取,默认为0 。
count=WHOLE_ARRAY
[in] 复制数组的数量,默认全部数组复制(count=WHOLE_ARRAY).
返回值
返回复制元素的数量
注意
如果参数count < 0 或 count > src_size - src_start,则表示所有余下的数组部分都将被复制,数组从左至右复制。对于一个时间序列数组(时间序列数组是倒序的)来说,正确的开始位置为定义调整后从左至右进行复制。如果数组自身复制到自身,则结果未定义。
(时间序列是颠倒的数组,第一个元素在最右边,最后一个元素在最左边。时间序列是用来存储历史价格数据并包含时间信息,我们可以看见时间序列最右边是最新的报价数据,而最左边是最旧的报价数据。因此时间序列以0开始索引编号,包括交易品种的最新的报价信息。如果时间序列包括每日时间列表的数据,当前尚未收盘的日期会显示在索引0的位置,而索引1的位置会显示昨天的数据。)
如果数组是不同类型的,在复制时,它将尝试把 源数组 的每个元素转换为 目标数组 的类型。一个字符串数组只能被复制到一个字符串数组中。不复制包含需要初始化的对象的 类 和 结构 的数组。可以将一个结构数组复制到同一类型的结构数组中。
对于在时间序列中使用索引的动态数组,目标数组的大小会自动增加到复制数据的数量(如果后者超过数组大小)。目标数组大小不会自动减少。 示例:
#property description "The indicator highlights the candlesticks that are local"
#property description "highs and lows. Interval length for finding"
#property description "extreme values should be found using an input parameters."
// 该指标突出显示了一段行情中 最高 和 最低的K线柱。寻找极端值的区间长度应该使用输入参数找到。
//--- 指标设置
#property indicator_chart_window
#property indicator_buffers 5
#property indicator_plots 1
//---- 绘制
#property indicator_label1 "Extremums"
#property indicator_type1 DRAW_COLOR_CANDLES
#property indicator_color1 clrLightSteelBlue,clrRed,clrBlue
#property indicator_style1 STYLE_SOLID
#property indicator_width1 1
//--- 预定义常量
#define INDICATOR_EMPTY_VALUE 0.0
//--- 输入参数
input int InpNum=4; // 区间长度。表示取前后 4根K线来比较,当前K线是否一个 (最高/最低)价格
//--- 指标缓冲区
double ExtOpen[];
double ExtHigh[];
double ExtLow[];
double ExtClose[];
double ExtColor[];
//--- 全局变量
int ExtStart=0; // 第一个蜡烛图的指数不是一个极值
int ExtCount=0; // 区间的非极值数量
//+------------------------------------------------------------------+
//| 填写非极值蜡烛图 |
//+------------------------------------------------------------------+
void FillCandles(const double &open[],const double &high[],
const double &low[],const double &close[])
{
//--- 填写蜡烛图
ArrayCopy(ExtOpen,open,ExtStart,ExtStart,ExtCount);
ArrayCopy(ExtHigh,high,ExtStart,ExtStart,ExtCount);
ArrayCopy(ExtLow,low,ExtStart,ExtStart,ExtCount);
ArrayCopy(ExtClose,close,ExtStart,ExtStart,ExtCount);
}
//+------------------------------------------------------------------+
//| 自定义指标初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 指标缓存映射
SetIndexBuffer(0,ExtOpen);
SetIndexBuffer(1,ExtHigh);
SetIndexBuffer(2,ExtLow);
SetIndexBuffer(3,ExtClose);
SetIndexBuffer(4,ExtColor,INDICATOR_COLOR_INDEX);
//--- 指定值,不显示
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,INDICATOR_EMPTY_VALUE);
//--- 指定用于在数据窗口显示的指标缓存名称
PlotIndexSetString(0,PLOT_LABEL,"Open;High;Low;Close");
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 自定义指标的迭代函数 |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
//--- 在时间序列设置直接索引
ArraySetAsSeries(open,false);
ArraySetAsSeries(high,false);
ArraySetAsSeries(low,false);
ArraySetAsSeries(close,false);
//--- 柱形变量计算开始
int start=prev_calculated;
//--- 开始的InpNum*2柱不执行计算
if(start==0)
{
start+=InpNum*2;
ExtStart=0;
ExtCount=0;
}
//--- 如果只形成柱,检查下一个潜在极值
if(rates_total-start==1)
start--;
//--- 检查极值的柱形索引
int ext;
//--- 指标值计算循环
for(int i=start;i<rates_total-1;i++)
{
//--- 在i柱上无初始绘制
ExtOpen[i]=0;
ExtHigh[i]=0;
ExtLow[i]=0;
ExtClose[i]=0;
//--- 用于检查的极值指数
ext=i-InpNum;
//--- 检查本地最大值
if(IsMax(high,ext))
{
//--- 强调极值蜡烛图
ExtOpen[ext]=open[ext];
ExtHigh[ext]=high[ext];
ExtLow[ext]=low[ext];
ExtClose[ext]=close[ext];
ExtColor[ext]=1;
//--- 用中间色突出其他蜡烛图直至极值
FillCandles(open,high,low,close);
//--- 改变变量颜色
ExtStart=ext+1;
ExtCount=0;
//--- 传递到下一个迭代
continue;
}
//--- 检查本地最小值
if(IsMin(low,ext))
{
//--- 突出极值蜡烛图
ExtOpen[ext]=open[ext];
ExtHigh[ext]=high[ext];
ExtLow[ext]=low[ext];
ExtClose[ext]=close[ext];
ExtColor[ext]=2;
//--- 用中间色突出其他蜡烛图直至极值
FillCandles(open,high,low,close);
//--- 改变变量值
ExtStart=ext+1;
ExtCount=0;
//--- 传递到下一个迭代
continue;
}
//--- 增加无极值间隔数量
ExtCount++;
}
//--- 为下次调用返回 prev_calculated 值
return(rates_total);
}
//+------------------------------------------------------------------+
//| 检查当前数组元素是否本地最高 |
//+------------------------------------------------------------------+
bool IsMax(const double &price[],const int ind)
{
//--- 间隔开始变量
int i=ind-InpNum;
//--- 间隔时间结束
int finish=ind+InpNum+1;
//--- 检查上半部间隔
for(;i<ind;i++)
{
if(price[ind]<=price[i])
return(false);
}
//--- 检查下半部间隔
for(i=ind+1;i<finish;i++)
{
if(price[ind]<=price[i])
return(false);
}
//--- 这是一个极值
return(true);
}
//+------------------------------------------------------------------+
//| 检查当前数组元素是否是本地最低 |
//+------------------------------------------------------------------+
bool IsMin(const double &price[],const int ind)
{
//--- 间隔开始变量
int i=ind-InpNum;
//--- 间隔时间结束
int finish=ind+InpNum+1;
//--- 检查上半部间隔
for(;i<ind;i++)
{
if(price[ind]>=price[i])
return(false);
}
//--- 检查下半部间隔
for(i=ind+1;i<finish;i++)
{
if(price[ind]>=price[i])
return(false);
}
//--- 这是一个极值
return(true);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# 6.3 ArrayCompare
此函数返回比较两个相同类型的数组的结果。它可以用来比较 简单类型 或 没有复杂对象的自定义结构的数组。自定义结构不可以包括 字符串,动态数组,类 和 其它没有 复杂对象 的 结构。
int ArrayCompare(
const void& array1[], // 第一数组
const void& array2[], // 第二数组
uint start1=0, // 第一数组的初始索引编号位置的偏移值
uint start2=0, // 第二数组的初始索引编号位置的偏移值
uint count=WHOLE_ARRAY // 元素比较的数量
);
2
3
4
5
6
7
参数
array1[]
[in] 第一数组。
array2[]
[in] 第二数组。
start1=0
[in] 第一数组的元素初始索引编号,即开始比较的位置。默认开始索引编号 —— 0。
start2=0
[in] 第二数组的元素初始索引编号,即开始比较的位置。默认开始索引编号 —— 0。
count=WHOLE_ARRAY
[in] 要比较的元素数量。两种数组的所有元素默认都参与比较 (count=WHOLE_ARRAY)。
返回值 • -1, 如果 array1[] 小于 array2[] • 0, 如果 array1[] 等于 array2[] • 1, 如果 array1[] 大于 array2[] • -2, 如果出现错误。错误的原因可能是比较数组的类型不兼容,或者start1、start2或count值导致索引位置超出数组范围,而出现错误。
注意 如果数组的大小和count=WHOLE_ARRAY不同,那么当一个数组是另一个数组的准确子集时。那么本函数将不会返回0(数组不会被认为是相等的)。在这种情况下,比较数组大小的结果:如果array1[] 小于array2[] 将返回: -1,否则为1。
# 6.4 ArrayFree
释放任何动态数组的缓冲区,并将零维的大小设置为0。
void ArrayFree(
void& array[] // 数组
);
2
3
参数
array[]
[in] 动态数组。
返回值
没有返回值
注意考虑到要一次性释放所有使用的内存并且数组的主要工作由访问指标缓存组成,那么使用ArrayFree() 函数的需求不会太频繁地出现。缓冲区的大小由终端的执行子系统自动管理。
如果需要在应用程序的复杂动态环境中手动管理内存,则ArrayFree()函数允许用户明确地立即释放已经不必要的动态数组占用的内存。
示例:
#include <Controls\Dialog.mqh>
#include <Controls\Button.mqh>
#include <Controls\Label.mqh>
#include <Controls\ComboBox.mqh>
//--- 预定义常量
#define X_START 0
#define Y_START 0
#define X_SIZE 580
#define Y_SIZE 800
//+------------------------------------------------------------------+
//| 内存工作的对话类 |
//+------------------------------------------------------------------+
class CMemoryControl : public CAppDialog
{
private:
//--- 数组大小
int m_arr_size;
//--- 数组
char m_arr_char[];
int m_arr_int[];
float m_arr_float[];
double m_arr_double[];
long m_arr_long[];
//--- 标签
CLabel m_lbl_memory_physical;
CLabel m_lbl_memory_total;
CLabel m_lbl_memory_available;
CLabel m_lbl_memory_used;
CLabel m_lbl_array_size;
CLabel m_lbl_array_type;
CLabel m_lbl_error;
CLabel m_lbl_change_type;
CLabel m_lbl_add_size;
//--- 按钮
CButton m_button_add;
CButton m_button_free;
//--- 组合框
CComboBox m_combo_box_step;
CComboBox m_combo_box_type;
//--- 来自组合框的当前的数组类型值
int m_combo_box_type_value;
public:
CMemoryControl(void);
~CMemoryControl(void);
//--- 类对象创建方法
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
//--- 图表事件处理程序
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
protected:
//--- 创建标签
bool CreateLabel(CLabel &lbl,const string name,const int x,const int y,const string str,const int font_size,const int clr);
//--- 创建控制元素
bool CreateButton(CButton &button,const string name,const int x,const int y,const string str,const int font_size,const int clr);
bool CreateComboBoxStep(void);
bool CreateComboBoxType(void);
//--- 事件处理程序
void OnClickButtonAdd(void);
void OnClickButtonFree(void);
void OnChangeComboBoxType(void);
//--- 当前数组工作的方法
void CurrentArrayFree(void);
bool CurrentArrayAdd(void);
};
//+------------------------------------------------------------------+
//| 释放当前数组内存 |
//+------------------------------------------------------------------+
void CMemoryControl::CurrentArrayFree(void)
{
//--- 重置数组大小
m_arr_size=0;
//--- 释放数组
if(m_combo_box_type_value==0)
ArrayFree(m_arr_char);
if(m_combo_box_type_value==1)
ArrayFree(m_arr_int);
if(m_combo_box_type_value==2)
ArrayFree(m_arr_float);
if(m_combo_box_type_value==3)
ArrayFree(m_arr_double);
if(m_combo_box_type_value==4)
ArrayFree(m_arr_long);
}
//+------------------------------------------------------------------+
//| 尝试为当前数组增加内存 |
//+------------------------------------------------------------------+
bool CMemoryControl::CurrentArrayAdd(void)
{
//--- 如果所用内存大小超过物理内存大小,则退出
if(TerminalInfoInteger(TERMINAL_MEMORY_PHYSICAL)/TerminalInfoInteger(TERMINAL_MEMORY_USED) < 2)
return(false);
//--- 根据当前类型尝试分配内存
if(m_combo_box_type_value==0 && ArrayResize(m_arr_char,m_arr_size)==-1)
return(false);
if(m_combo_box_type_value==1 && ArrayResize(m_arr_int,m_arr_size)==-1)
return(false);
if(m_combo_box_type_value==2 && ArrayResize(m_arr_float,m_arr_size)==-1)
return(false);
if(m_combo_box_type_value==3 && ArrayResize(m_arr_double,m_arr_size)==-1)
return(false);
if(m_combo_box_type_value==4 && ArrayResize(m_arr_long,m_arr_size)==-1)
return(false);
//--- 分配内存
return(true);
}
//+------------------------------------------------------------------+
//| 事件处理 |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CMemoryControl)
ON_EVENT(ON_CLICK,m_button_add,OnClickButtonAdd)
ON_EVENT(ON_CLICK,m_button_free,OnClickButtonFree)
ON_EVENT(ON_CHANGE,m_combo_box_type,OnChangeComboBoxType)
EVENT_MAP_END(CAppDialog)
//+------------------------------------------------------------------+
//| 构造函数 |
//+------------------------------------------------------------------+
CMemoryControl::CMemoryControl(void)
{
}
//+------------------------------------------------------------------+
//| 析构函数 |
//+------------------------------------------------------------------+
CMemoryControl::~CMemoryControl(void)
{
}
//+------------------------------------------------------------------+
//| 类对象创建方法 |
//+------------------------------------------------------------------+
bool CMemoryControl::Create(const long chart,const string name,const int subwin,
const int x1,const int y1,const int x2,const int y2)
{
//--- 创建基本类对象
if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
//--- 准备标签字符串
string str_physical="物理内存 = "+(string)TerminalInfoInteger(TERMINAL_MEMORY_PHYSICAL)+" Mb";
string str_total="内存总量 = "+(string)TerminalInfoInteger(TERMINAL_MEMORY_TOTAL)+" Mb";
string str_available="可用内存 = "+(string)TerminalInfoInteger(TERMINAL_MEMORY_AVAILABLE)+" Mb";
string str_used="已用内存 = "+(string)TerminalInfoInteger(TERMINAL_MEMORY_USED)+" Mb";
//--- 创建标签
if(!CreateLabel(m_lbl_memory_physical,"physical_label",X_START+10,Y_START+5,str_physical,12,clrBlack))
return(false);
if(!CreateLabel(m_lbl_memory_total,"total_label",X_START+10,Y_START+30,str_total,12,clrBlack))
return(false);
if(!CreateLabel(m_lbl_memory_available,"available_label",X_START+10,Y_START+55,str_available,12,clrBlack))
return(false);
if(!CreateLabel(m_lbl_memory_used,"used_label",X_START+10,Y_START+80,str_used,12,clrBlack))
return(false);
if(!CreateLabel(m_lbl_array_type,"type_label",X_START+10,Y_START+105,"数组类型 = double",12,clrBlack))
return(false);
if(!CreateLabel(m_lbl_array_size,"size_label",X_START+10,Y_START+130,"数组大小 = 0",12,clrBlack))
return(false);
if(!CreateLabel(m_lbl_error,"error_label",X_START+10,Y_START+155,"",12,clrRed))
return(false);
if(!CreateLabel(m_lbl_change_type,"change_type_label",X_START+10,Y_START+185,"更改类型",10,clrBlack))
return(false);
if(!CreateLabel(m_lbl_add_size,"add_size_label",X_START+10,Y_START+230,"添加到数组",10,clrBlack))
return(false);
//--- 创建控制元素
if(!CreateButton(m_button_add,"add_button",X_START+15,Y_START+295,"添加",12,clrBlue))
return(false);
if(!CreateButton(m_button_free,"free_button",X_START+125,Y_START+295,"释放",12,clrBlue))
return(false);
if(!CreateComboBoxType())
return(false);
if(!CreateComboBoxStep())
return(false);
//--- 初始变量
m_arr_size=0;
//--- 成功执行
return(true);
}
//+------------------------------------------------------------------+
//| 创建按钮 |
//+------------------------------------------------------------------+
bool CMemoryControl::CreateButton(CButton &button,const string name,const int x,
const int y,const string str,const int font_size,
const int clr)
{
//--- 创建按钮
if(!button.Create(m_chart_id,name,m_subwin,x,y,x+80,y+80))
return(false);
//--- 文本
if(!button.Text(str))
return(false);
//--- 字体大小
if(!button.FontSize(font_size))
return(false);
//--- 标签颜色
if(!button.Color(clr))
return(false);
//--- 添加按钮到控制元素
if(!Add(button))
return(false);
//--- 成功执行
return(true);
}
//+------------------------------------------------------------------+
//| 创建数组大小组合框 |
//+------------------------------------------------------------------+
bool CMemoryControl::CreateComboBoxStep(void)
{
//--- 创建组合框
if(!m_combo_box_step.Create(m_chart_id,"step_combobox",m_subwin,X_START+150,Y_START+185,X_START+280,Y_START+205))
return(false);
//--- 添加元素到组合框
if(!m_combo_box_step.ItemAdd("100 000",100000))
return(false);
if(!m_combo_box_step.ItemAdd("1 000 000",1000000))
return(false);
if(!m_combo_box_step.ItemAdd("10 000 000",10000000))
return(false);
if(!m_combo_box_step.ItemAdd("100 000 000",100000000))
return(false);
//--- 设置当前组合框元素
if(!m_combo_box_step.SelectByValue(1000000))
return(false);
//--- 添加组合框到控制元素
if(!Add(m_combo_box_step))
return(false);
//--- 成功执行
return(true);
}
//+------------------------------------------------------------------+
//| 创建数组类型组合框 |
//+------------------------------------------------------------------+
bool CMemoryControl::CreateComboBoxType(void)
{
//--- 创建组合框
if(!m_combo_box_type.Create(m_chart_id,"type_combobox",m_subwin,X_START+150,Y_START+235,X_START+280,Y_START+255))
return(false);
//--- 添加元素到组合框
if(!m_combo_box_type.ItemAdd("char",0))
return(false);
if(!m_combo_box_type.ItemAdd("int",1))
return(false);
if(!m_combo_box_type.ItemAdd("float",2))
return(false);
if(!m_combo_box_type.ItemAdd("double",3))
return(false);
if(!m_combo_box_type.ItemAdd("long",4))
return(false);
//--- 设置当前组合框元素
if(!m_combo_box_type.SelectByValue(3))
return(false);
//--- 存储当前组合框元素
m_combo_box_type_value=3;
//--- 添加组合框到控制元素
if(!Add(m_combo_box_type))
return(false);
//--- 成功执行
return(true);
}
//+------------------------------------------------------------------+
//| 创建标签 |
//+------------------------------------------------------------------+
bool CMemoryControl::CreateLabel(CLabel &lbl,const string name,const int x,
const int y,const string str,const int font_size,
const int clr)
{
//--- 创建标签
if(!lbl.Create(m_chart_id,name,m_subwin,x,y,0,0))
return(false);
//--- 文本
if(!lbl.Text(str))
return(false);
//--- 字体大小
if(!lbl.FontSize(font_size))
return(false);
//--- 颜色
if(!lbl.Color(clr))
return(false);
//--- 添加标签到控制元素
if(!Add(lbl))
return(false);
//--- 成功
return(true);
}
//+------------------------------------------------------------------+
//| 点击“添加”按钮事件的处理程序 |
//+------------------------------------------------------------------+
void CMemoryControl::OnClickButtonAdd(void)
{
//--- 提高数组大小
m_arr_size+=(int)m_combo_box_step.Value();
//--- 尝试为当前数组分配内存
if(CurrentArrayAdd())
{
//--- 分配内存,在屏幕上展示当前状态
m_lbl_memory_available.Text("可用内存 = "+(string)TerminalInfoInteger(TERMINAL_MEMORY_AVAILABLE)+" Mb");
m_lbl_memory_used.Text("已用内存 = "+(string)TerminalInfoInteger(TERMINAL_MEMORY_USED)+" Mb");
m_lbl_array_size.Text("数组大小 = "+IntegerToString(m_arr_size));
m_lbl_error.Text("");
}
else
{
//--- 分配内存失败,显示错误信息
m_lbl_error.Text("Array is too large, error!");
//--- 返回之前的数组大小
m_arr_size-=(int)m_combo_box_step.Value();
}
}
//+------------------------------------------------------------------+
//| 点击“释放”按钮事件的处理程序 |
//+------------------------------------------------------------------+
void CMemoryControl::OnClickButtonFree(void)
{
//--- 释放当前数组的内存
CurrentArrayFree();
//--- 在屏幕上显示当前状态
m_lbl_memory_available.Text("可用内存 = "+(string)TerminalInfoInteger(TERMINAL_MEMORY_AVAILABLE)+" Mb");
m_lbl_memory_used.Text("已用内存 = "+(string)TerminalInfoInteger(TERMINAL_MEMORY_USED)+" Mb");
m_lbl_array_size.Text("数组大小 = 0");
m_lbl_error.Text("");
}
//+------------------------------------------------------------------+
//| 组合框更改事件的处理程序 |
//+------------------------------------------------------------------+
void CMemoryControl::OnChangeComboBoxType(void)
{
//--- 检查数组类型是否更改
if(m_combo_box_type.Value()!=m_combo_box_type_value)
{
//--- 释放当前数组内存
OnClickButtonFree();
//--- 使用另一个数组类型
m_combo_box_type_value=(int)m_combo_box_type.Value();
//--- 在屏幕上显示新数组类型
if(m_combo_box_type_value==0)
m_lbl_array_type.Text("数组类型 = char");
if(m_combo_box_type_value==1)
m_lbl_array_type.Text("数组类型 = int");
if(m_combo_box_type_value==2)
m_lbl_array_type.Text("数组类型 = float");
if(m_combo_box_type_value==3)
m_lbl_array_type.Text("数组类型 = double");
if(m_combo_box_type_value==4)
m_lbl_array_type.Text("数组类型 = long");
}
}
//--- CMemoryControl 类对象
CMemoryControl ExtDialog;
//+------------------------------------------------------------------+
//| 专家初始化类型 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 创建对话
if(!ExtDialog.Create(0,"内存控制",0,X_START,Y_START,X_SIZE,Y_SIZE))
return(INIT_FAILED);
//--- 启动
ExtDialog.Run();
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 专家去初始化函数 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
ExtDialog.Destroy(reason);
}
//+------------------------------------------------------------------+
//| 专家图表事件函数 |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
ExtDialog.ChartEvent(id,lparam,dparam,sparam);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
# 6.5 ArrayGetAsSeries
检测数组索引的方向(是从左到右,还是 从右到左)
bool ArrayGetAsSeries(
const void& array[] // 用于检测的数组
);
2
3
参数
array[]
[in] 检测数组
返回值
如果指定的数组设置有AS_SERIES标帜,则返回true,即对数组的访问将和时间序列数组一样,从后往前。时间序列不同于普通的数组,因为时间序列的元素索引编号是从结尾到开头来执行的(数据从 最新的 到 最旧的)。
注意
要检查数组是否属于时间序列,请使用ArrayIsSeries()函数。将报价数据数组作为输入参数传递到OnCalculate()函数中时,不需要将索引方向与时间序列中相同。可以使用ArraySetAsSeries()函数设置必要的索引方向。
示例:
#property description "Indicator calculates absolute values of the difference between"
#property description "Open and Close or High and Low prices displaying them in a separate subwindow"
#property description "as a histogram."
//本指标计算 OCHL(开盘,收盘,最高,最低)价格之间的绝对差值,将它们以柱状图的形式显示在副图中。
//---指标设置
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots 1
//---- 绘制
#property indicator_type1 DRAW_HISTOGRAM
#property indicator_style1 STYLE_SOLID
#property indicator_width1 3
//--- 输入参数
input bool InpAsSeries=true; // 指标缓冲区的标引导向
input bool InpPrices=true; // 计算价格 (true - 开盘价,收盘价; false - 最高价,最低价)
//--- 指标缓冲区
double ExtBuffer[];
//+------------------------------------------------------------------+
//| 计算指标的值 |
//+------------------------------------------------------------------+
void CandleSizeOnBuffer(const int rates_total,const int prev_calculated,
const double &first[],const double &second[],double &buffer[])
{
//--- 计算柱形的开始变量
int start=prev_calculated;
//--- 如果前一个订单号已经计算了指标值,那么使用最近的柱
if(prev_calculated>0)
start--;
//--- 定义数组的标引导向
bool as_series_first=ArrayGetAsSeries(first);
bool as_series_second=ArrayGetAsSeries(second);
bool as_series_buffer=ArrayGetAsSeries(buffer);
//--- 如果有必要,直接替代标引导向
if(as_series_first)
ArraySetAsSeries(first,false);
if(as_series_second)
ArraySetAsSeries(second,false);
if(as_series_buffer)
ArraySetAsSeries(buffer,false);
//--- 计算指标值
for(int i=start;i<rates_total;i++)
buffer[i]=MathAbs(first[i]-second[i]);
}
//+------------------------------------------------------------------+
//| 自定义指标初始函数 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 绑定指标缓冲区
SetIndexBuffer(0,ExtBuffer);
//--- 在指标缓冲区设置标引元素
ArraySetAsSeries(ExtBuffer,InpAsSeries);
//--- 检查指标计算的价格
if(InpPrices)
{
//--- 开盘价和收盘价
PlotIndexSetString(0,PLOT_LABEL,"BodySize");
//--- 设置指标颜色
PlotIndexSetInteger(0,PLOT_LINE_COLOR,clrOrange);
}
else
{
//--- 最高价和最低价
PlotIndexSetString(0,PLOT_LABEL,"ShadowSize");
//--- 设置指标颜色
PlotIndexSetInteger(0,PLOT_LINE_COLOR,clrDodgerBlue);
}
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 自定义指标迭代函数 |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
//--- 根据标识值计算指标
if(InpPrices)
CandleSizeOnBuffer(rates_total,prev_calculated,open,close,ExtBuffer);
else
CandleSizeOnBuffer(rates_total,prev_calculated,high,low,ExtBuffer);
//--- 为下次调用返回prev_calculated值
return(rates_total);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
相关参考 访问时间序列和指标数据 ,ArraySetAsSeries
# 6.6 ArrayInitialize
函数通过预设值初始化一个数组。 初始化字符型数组
int ArrayInitialize(
char array[], // 初始化的数组
char value // 将被设置的值
);
2
3
4
初始化短整型数组
int ArrayInitialize(
short array[], // 初始化的数组
short value // 将被设置的值
);
2
3
4
初始化长整型数组
int ArrayInitialize(
long array[], // 初始化的数组
long value // 将被设置的值
);
2
3
4
初始化浮点型数组
int ArrayInitialize(
float array[], // 初始化的数组
float value // 将被设置的值
);
2
3
4
初始化双精度型数组
int ArrayInitialize(
double array[], // 初始化的数组
double value // 将被设置的值
);
2
3
4
初始化布尔型数组
int ArrayInitialize(
bool array[], // 初始化的数组
bool value // 将被设置的值
);
2
3
4
初始化无符号整型数组
int ArrayInitialize(
uint array[], // 初始化的数组
uint value // 将被设置的值
);
2
3
4
参数
array[]
[out] 需要初始化的数值数组
value
[in] 为所有数组元素建立新值
返回值
初始化元素的数量。
注意
ArrayResize()函数允许设置一个数组的大小,以便在没有内存的物理迁移的情况下进一步扩展。它是为了更好的性能而实现的,因为内存迁移的操作相当缓慢。
使用ArrayInitialize(数组,init_val)初始化数组并不意味着初始化的值与分配给该数组的保留元素相同。在使用ArrayResize()函数进一步扩展数组时,将在数组的末尾添加元素,它们的值将是未定义的,在大多数情况下将不等于init_value。
示例:
void OnStart()
{
//--- 动态数组
double array[];
//--- 数组大小设为100个元素并为另10个元素保留缓冲区
ArrayResize(array,100,10);
//--- 初始化带有EMPTY_VALUE=DBL_MAX值的数组元素
ArrayInitialize(array,EMPTY_VALUE);
Print("Values of 10 last elements after initialization");
for(int i=90;i < 100;i++) printf("array[%d] = %G",i,array[i]);
//--- 数组扩展5个元素
ArrayResize(array,105);
Print("Values of 10 last elements after ArrayResize(array,105)");
//--- 最后的5个数组值可以从保留的缓冲区获得
for(int i=95;i < 105;i++) printf("array[%d] = %G",i,array[i]);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 6.7 ArrayFill
此函数以指定值填充数组。
void ArrayFill(
void& array[], // 数组
uint start, // 开始标引
uint count, // 填充的元素数量
void value // 值
);
2
3
4
5
6
参数
array[]
[out] 简单类型的数组 (char, uchar, short, ushort, int, uint, long, ulong, bool, color, datetime, float, double)。
start
[in] 开始索引编号。在这种情况下,指定的AS_SERIES 标帜被忽略。
count
[in] 填充的元素数量。
value
[in] 填充数组的值。
返回值
无返回值。
注意
当调用ArrayFill() 函数时,正常的索引编号方向(从左至右)始终隐藏。它意味着使用ArraySetAsSeries()函数改变访问数组元素的顺序被忽略。
在ArrayFill()函数处理的情况下,多维数组显示为一维数组。例如,array[2][4] 处理为array[8]。 因此,当使用该数组时,您可以指定初始元素的索引等于5。因此,为 array[2][4] 调用ArrayFill(array, 5, 2, 3.14),用3.14来填充array[1][1] 和 array[1][2]。
例如:
void OnStart()
{
//--- 声明动态数组
int a[];
//--- 设置大小
ArrayResize(a,10);
//--- 用123填充前5个元素
ArrayFill(a,0,5,123);
//--- 用456填充后5个元素
ArrayFill(a,5,5,456);
//--- 显示值
for(int i=0;i<ArraySize(a);i++) printf("a[%d] = %d",i,a[i]);
}
2
3
4
5
6
7
8
9
10
11
12
13
# 6.8 ArrayIsDynamic
此函数检查数组是否为动态的。
bool ArrayIsDynamic(
const void& array[] // 被检测的数组
);
2
3
参数
array[]
[in] 检测数组.
返回值
数组是动态的,返回 true,否则返回 false。
示例:
#property description "This indicator does not calculate values. It makes a single attempt to"
#property description "apply the call of ArrayFree() function to three arrays: dynamic one, static one and"
#property description "an indicator buffer. Results are shown in Experts journal."
//这个指标不计算值。它只是尝试调用ArrayFree()函数应用到三个数组:动态的、静态的和指标缓冲数组。
//--- 指标设置
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots 1
//--- 全局变量
double ExtDynamic[]; // 动态数组
double ExtStatic[100]; // 静态数组
bool ExtFlag=true; // 标识
double ExtBuff[]; // 指标缓冲区
//+------------------------------------------------------------------+
//| 自定义指标初始函数 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 为数组分配内存
ArrayResize(ExtDynamic,100);
//--- 指标缓冲区映射
SetIndexBuffer(0,ExtBuff);
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0);
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 自定义指标迭代函数 |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
//--- 执行一个分析
if(ExtFlag)
{
//--- 尝试释放数组内存
//--- 1. 动态数组
Print("+============================+");
Print("1. 检查动态数组:");
Print("释放前数组占用的内存大小 = ",ArraySize(ExtDynamic));
Print("这是个动态数组吗? = ",ArrayIsDynamic(ExtDynamic) ? "Yes" : "No");
//--- 尝试释放数组内存
ArrayFree(ExtDynamic);
Print("释放后数组占用的内存大小 = ",ArraySize(ExtDynamic));
//--- 2. 静态数组
Print("2. 检查静态数组:");
Print("释放前数组占用的内存大小 = ",ArraySize(ExtStatic));
Print("这是个动态数组吗? = ",ArrayIsDynamic(ExtStatic) ? "Yes" : "No");
//--- 尝试释放数组内存
ArrayFree(ExtStatic);
Print("释放后数组占用的内存大小 = ",ArraySize(ExtStatic));
//--- 3. 指标缓冲区
Print("3. 检查指标缓冲数组:");
Print("释放前数组占用的内存大小 = ",ArraySize(ExtBuff));
Print("这是个动态数组吗? = ",ArrayIsDynamic(ExtBuff) ? "Yes" : "No");
//--- 尝试释放数组内存
ArrayFree(ExtBuff);
Print("释放后数组占用的内存大小 = ",ArraySize(ExtBuff));
//--- 改变标识的值
ExtFlag=false;
}
//--- 为下次调用返回prev_calculated值
return(rates_total);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
ArrayIsSeries 此函数检查数组是否为 时间序列数组。
bool ArrayIsSeries(
const void& array[] // 被检测的数组
);
2
3
参数
array[]
[in] 被检测的数组
返回值
如果检测数组是 时间序列数组,就返回TRUE,否则返回FALSE。数组以形式参数传递到OnCalculate()函数必须通过 ArrayGetAsSeries()检测访问数组元素的顺序
示例:
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots 1
//---- 标签图1
#property indicator_label1 "Label1"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrRed
#property indicator_style1 STYLE_SOLID
#property indicator_width1 1
//--- 指标缓冲区
double Label1Buffer[];
//+------------------------------------------------------------------+
//| 自定义指标初始化函数 |
//+------------------------------------------------------------------+
void OnInit()
{
//--- 指标缓冲区绘图
SetIndexBuffer(0,Label1Buffer,INDICATOR_DATA);
//---
}
//+------------------------------------------------------------------+
//| 自定义指标循环函数 |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
//---
if(ArrayIsSeries(open))
Print("open[] is timeseries");
else
Print("open[] is not timeseries!!!");
//--- 为下次调用返回prev_calculated值
return(rates_total);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
相关参考 访问时间序列和指标
# 6.9 ArrayResize
函数建立新的第一维大小
int ArrayResize(
void& array[], // 引用传递的数组
int new_size, // 新数组大小
int reserve_size=0 // 保留尺寸值 (过量)
);
2
3
4
5
参量
array[]
[out] 数组变化尺寸
new_size
[in] 第一维度新尺寸
reserve_size=0
[in] 获得存储的分散式大小
返回值
如果执行成功,在数组中改变规格后返回所有元素计数,否则,返回-1,数组不调整大小。
如果ArrayResize() 应用于静态数组,timeseries或指标缓冲区,数组大小保持一致 –这些数组将不会被重新分配。在这种情况下,如果new_size<=ArraySize(数组),函数将只会返回 new_size;否则将会返回-1值。
注释
该函数只能应用在 动态数组。应该注意的是您不能改变通过SetIndexBuffer()函数分配的作为指标缓冲区的动态数组的大小。对于指标缓冲区,调整大小的所有操作都通过程序端的运行时间子系统来执行。
数组中的元素总数不能超过 2147483647。
随着频繁的内存分配,推荐使用设置存储以减少物理内存分配数量的第三方参数。后来的ArrayResize所有调用都不能导致重新分配物理内存,只是会在保留内存内改变第一数组维度的大小。应谨记,第三方参数只能在物理内存分配期间使用。例如:
ArrayResize(arr,1000,1000); for(int i=1;i < 3000;i++) ArrayResize(arr,i,1000);
假若这样,内存将被重新分配两次,第一次是输入2000元素循环之前(数组大小将设为1000),第二次是i等于3000.如果我们跳过第三方参数,将会有2000重新分配物理内存,这将使程序减速。
例如:
//+------------------------------------------------------------------+
//| 脚本程序起始函数 |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 计数器
ulong start=GetTickCount();
ulong now;
int count=0;
//--- 用于快速版本维度的数组
double arr[];
ArrayResize(arr,100000,100000);
//--- 检查如何加速内存保留工作的变量
Print("--- Test Fast: ArrayResize(arr,100000,100000)");
for(int i=1;i<=300000;i++)
{
//--- 设置新数组大小指定储备100,000元素!
ArrayResize(arr,i,100000);
//--- 当到达整十整百的整数时,显示数组大小和花费的时间
if(ArraySize(arr)%100000==0)
{
now=GetTickCount();
count++;
PrintFormat("%d. ArraySize(arr)=%d Time=%d ms",count,ArraySize(arr),(now-start));
start=now;
}
}
//--- 现在显示,无保留内存的版本有多慢
double slow[];
ArrayResize(slow,100000,100000);
//---
count=0;
start=GetTickCount();
Print("---- Test Slow: ArrayResize(slow,100000)");
//---
for(int i=1;i<=300000;i++)
{
//--- 设置新的数组大小,但是无额外储备
ArrayResize(slow,i);
//--- 当到达整十整百的整数时,显示数组大小和花费的时间
if(ArraySize(slow)%100000==0)
{
now=GetTickCount();
count++;
PrintFormat("%d. ArraySize(slow)=%d Time=%d ms",count,ArraySize(slow),(now-start));
start=now;
}
}
}
//--- 脚本的示例结果
/*
Test_ArrayResize (EURUSD,H1) --- Test Fast: ArrayResize(arr,100000,100000)
Test_ArrayResize (EURUSD,H1) 1. ArraySize(arr)=100000 Time=0 ms
Test_ArrayResize (EURUSD,H1) 2. ArraySize(arr)=200000 Time=0 ms
Test_ArrayResize (EURUSD,H1) 3. ArraySize(arr)=300000 Time=0 ms
Test_ArrayResize (EURUSD,H1) ---- Test Slow: ArrayResize(slow,100000)
Test_ArrayResize (EURUSD,H1) 1. ArraySize(slow)=100000 Time=0 ms
Test_ArrayResize (EURUSD,H1) 2. ArraySize(slow)=200000 Time=0 ms
Test_ArrayResize (EURUSD,H1) 3. ArraySize(slow)=300000 Time=228511 ms
*/
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
另见
ArrayInitialize
# 6.10 ArrayMaximum
在多维数值数组中,搜索第一个维度中的最大的那个元素。
int ArrayMaximum(
const void& array[], // 用于搜索的数组
int start=0, // 搜索开始的索引编号
int count=WHOLE_ARRAY // 搜索元素的数量
);
2
3
4
5
参数
array[]
[in] 数值数组,建立搜寻
start=0
[in] 开始搜索的索引编号
count=WHOLE_ARRAY
[in] 搜索元素的数量。默认在整个数组 (count=WHOLE_ARRAY)中搜索。
返回值
该函数返回被找到的元素的索引编号,并考虑到数组序列。如果失败,则返回 -1。
注意
搜索最大值时考虑AS_SERIES标帜。
函数ArrayMaximum 和 ArrayMinimum 接受任何维度的数组为参数。然而,搜索却始终应用于第一(0)维度。
示例:
见下节
# 6.11 ArrayMinimum
在多维数值数组中,搜索第一个维度中的最小的那个元素。
int ArrayMinimum(
const void& array[], // 用来搜索的数组
int start=0, // 搜索开始的索引编号
int count=WHOLE_ARRAY // 搜索元素的数量
);
2
3
4
5
参数
array[]
[in] 数值数组,建立搜寻
start=0
[in] 开始搜索的索引编号
count=WHOLE_ARRAY
[in] 搜索元素的数量。默认在整个数组 (count=WHOLE_ARRAY)中搜索。
返回值
该函数返回被找到的元素的索引编号,并考虑到数组序列。如果失败,则返回 -1。
注意
搜索最小值时考虑AS_SERIES标帜。
函数ArrayMaximum 和 ArrayMinimum 接受任何维度的数组为参数。然而,搜索却始终应用于第一(0)维度。
示例:
#property description "The indicator displays larger time frame's candlesticks on the current one."
//这个指标在当前图表上显示一个更大时间框架(默认H4)的K线柱。
//--- 指标设置
#property indicator_chart_window
#property indicator_buffers 16
#property indicator_plots 8
//---- 图 1
#property indicator_label1 "BearBody"
#property indicator_color1 clrSeaGreen,clrSeaGreen
//---- 图 2
#property indicator_label2 "BearBodyEnd"
#property indicator_color2 clrSeaGreen,clrSeaGreen
//---- 图 3
#property indicator_label3 "BearShadow"
#property indicator_color3 clrSalmon,clrSalmon
//---- 图 4
#property indicator_label4 "BearShadowEnd"
#property indicator_color4 clrSalmon,clrSalmon
//---- 图 5
#property indicator_label5 "BullBody"
#property indicator_color5 clrOlive,clrOlive
//---- 图 6
#property indicator_label6 "BullBodyEnd"
#property indicator_color6 clrOlive,clrOlive
//---- 图 7
#property indicator_label7 "BullShadow"
#property indicator_color7 clrSkyBlue,clrSkyBlue
//---- 图 8
#property indicator_label8 "BullShadowEnd"
#property indicator_color8 clrSkyBlue,clrSkyBlue
//--- 预定义常量
#define INDICATOR_EMPTY_VALUE 0.0
//--- 输入参数
input ENUM_TIMEFRAMES InpPeriod=PERIOD_H4; // 指标计算的时间范围
input datetime InpDateStart=D'2013.01.01 00:00'; // 分析起始日期
//--- 熊市蜡烛图的指标缓冲区
double ExtBearBodyFirst[];
double ExtBearBodySecond[];
double ExtBearBodyEndFirst[];
double ExtBearBodyEndSecond[];
double ExtBearShadowFirst[];
double ExtBearShadowSecond[];
double ExtBearShadowEndFirst[];
double ExtBearShadowEndSecond[];
//--- 牛市蜡烛图的指标缓冲区
double ExtBullBodyFirst[];
double ExtBullBodySecond[];
double ExtBullBodyEndFirst[];
double ExtBullBodyEndSecond[];
double ExtBullShadowFirst[];
double ExtBullShadowSecond[];
double ExtBullShadowEndFirst[];
double ExtBullShadowEndSecond[];
//--- 全局变量
datetime ExtTimeBuff[]; // 较大时间帧的时间缓冲区
int ExtSize=0; // 时间缓冲区大小
int ExtCount=0; // 时间缓冲区的标引
int ExtStartPos=0; // 指标计算的初始位置
bool ExtStartFlag=true; // 接收初始位置的辅助标识
datetime ExtCurrentTime[1]; // 生成较大时间帧柱形的最近时间
datetime ExtLastTime; // 较大时间帧的最近时间,执行计算
bool ExtBearFlag=true; // 标记定义编写数据订单熊市指标缓冲区
bool ExtBullFlag=true; // 标记定义编写数据订单牛市指标缓冲区
int ExtIndexMax=0; // 数组中最大元素标引
int ExtIndexMin=0; // 数组中最小元素标引
int ExtDirectionFlag=0; // 当前蜡烛图的价格移动方向
//--- 正确绘制蜡烛图开盘价和收盘价之间的转换
const double ExtEmptyBodySize=0.2*SymbolInfoDouble(Symbol(),SYMBOL_POINT);
//+------------------------------------------------------------------+
//| 填写蜡烛图的基本部分 |
//+------------------------------------------------------------------+
void FillCandleMain(const double &open[],const double &close[],
const double &high[],const double &low[],
const int start,const int last,const int fill_index,
int &index_max,int &index_min)
{
//--- 在数组中找出最大和最小元素的标引
index_max=ArrayMaximum(high,ExtStartPos,last-start+1); // 最高极值
index_min=ArrayMinimum(low,ExtStartPos,last-start+1); // 最低极值
//--- 定义当前时间帧填充多少柱
int count=fill_index-start+1;
//--- 如果首柱的收盘价超过最后的柱,那么蜡烛图为熊市
if(open[start]>close[last])
{
//--- 如果蜡烛图之前牛市,清空牛市指标缓冲区的值
if(ExtDirectionFlag!=-1)
ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,start,count);
//--- 熊市蜡烛图
ExtDirectionFlag=-1;
//--- 生成蜡烛图
FormCandleMain(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,open[start],
close[last],high[index_max],low[index_min],start,count,ExtBearFlag);
//--- 退出函数
return;
}
//--- 如果首柱的收盘价少于最后的柱,那么蜡烛图为牛市
if(open[start]<close[last])
{
//--- 如果蜡烛图之前为熊市,清空熊市指标缓冲区的值
if(ExtDirectionFlag!=1)
ClearCandle(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,start,count);
//--- 牛市蜡烛图
ExtDirectionFlag=1;
//--- 生成蜡烛图
FormCandleMain(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,close[last],
open[start],high[index_max],low[index_min],start,count,ExtBullFlag);
//--- 退出函数
return;
}
//--- 如果您在这部分函数,首柱开盘价等于
//--- 最后柱的收盘价;这种蜡烛图被认为熊市图
//--- 如果在那之前蜡烛图为牛市,清空牛市指标缓冲区的值
if(ExtDirectionFlag!=-1)
ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,start,count);
//--- 熊市蜡烛图
ExtDirectionFlag=-1;
//--- 如果收盘和开盘价相同,使用切换来正确显示
if(high[index_max]!=low[index_min])
FormCandleMain(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,open[start],
open[start]-ExtEmptyBodySize,high[index_max],low[index_min],start,count,ExtBearFlag);
else
FormCandleMain(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,
open[start],open[start]-ExtEmptyBodySize,high[index_max],
high[index_max]-ExtEmptyBodySize,start,count,ExtBearFlag);
}
//+------------------------------------------------------------------+
//| 填充蜡烛图末端 |
//+------------------------------------------------------------------+
void FillCandleEnd(const double &open[],const double &close[],
const double &high[],const double &low[],
const int start,const int last,const int fill_index,
const int index_max,const int index_min)
{
//--- 单柱时不要绘制
if(last-start==0)
return;
//--- 如果首柱的收盘价超过最后的柱,蜡烛图为熊市
if(open[start]>close[last])
{
//--- 生成蜡烛图末端
FormCandleEnd(ExtBearBodyEndFirst,ExtBearBodyEndSecond,ExtBearShadowEndFirst,ExtBearShadowEndSecond,
open[start],close[last],high[index_max],low[index_min],fill_index,ExtBearFlag);
//--- 退出函数
return;
}
//--- 如果首柱的收盘价小于最后的柱,蜡烛图为牛市
if(open[start]<close[last])
{
//--- 生成蜡烛图末端
FormCandleEnd(ExtBullBodyEndFirst,ExtBullBodyEndSecond,ExtBullShadowEndFirst,ExtBullShadowEndSecond,
close[last],open[start],high[index_max],low[index_min],fill_index,ExtBullFlag);
//--- 退出函数
return;
}
//--- 如果您在这部分函数,首柱开盘价等于
//--- 最后柱的收盘价;这种蜡烛图被认为熊市图
//--- 生成蜡烛图末端
if(high[index_max]!=low[index_min])
FormCandleEnd(ExtBearBodyEndFirst,ExtBearBodyEndSecond,ExtBearShadowEndFirst,ExtBearShadowEndSecond,open[start],
open[start]-ExtEmptyBodySize,high[index_max],low[index_min],fill_index,ExtBearFlag);
else
FormCandleEnd(ExtBearBodyEndFirst,ExtBearBodyEndSecond,ExtBearShadowEndFirst,ExtBearShadowEndSecond,open[start],
open[start]-ExtEmptyBodySize,high[index_max],high[index_max]-ExtEmptyBodySize,fill_index,ExtBearFlag);
}
//+------------------------------------------------------------------+
//| 自定义指标初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 检查指标周期
if(!CheckPeriod((int)Period(),(int)InpPeriod))
return(INIT_PARAMETERS_INCORRECT);
//--- 在前景显示价格数据
ChartSetInteger(0,CHART_FOREGROUND,0,1);
//--- 绑定指标缓冲区
SetIndexBuffer(0,ExtBearBodyFirst);
SetIndexBuffer(1,ExtBearBodySecond);
SetIndexBuffer(2,ExtBearBodyEndFirst);
SetIndexBuffer(3,ExtBearBodyEndSecond);
SetIndexBuffer(4,ExtBearShadowFirst);
SetIndexBuffer(5,ExtBearShadowSecond);
SetIndexBuffer(6,ExtBearShadowEndFirst);
SetIndexBuffer(7,ExtBearShadowEndSecond);
SetIndexBuffer(8,ExtBullBodyFirst);
SetIndexBuffer(9,ExtBullBodySecond);
SetIndexBuffer(10,ExtBullBodyEndFirst);
SetIndexBuffer(11,ExtBullBodyEndSecond);
SetIndexBuffer(12,ExtBullShadowFirst);
SetIndexBuffer(13,ExtBullShadowSecond);
SetIndexBuffer(14,ExtBullShadowEndFirst);
SetIndexBuffer(15,ExtBullShadowEndSecond);
//--- 设置一些属性值来创建指标
for(int i=0;i<8;i++)
{
PlotIndexSetInteger(i,PLOT_DRAW_TYPE,DRAW_FILLING); // 图形结构类型
PlotIndexSetInteger(i,PLOT_LINE_STYLE,STYLE_SOLID); // 绘制线型风格
PlotIndexSetInteger(i,PLOT_LINE_WIDTH,1); // 绘制线型宽度
}
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 自定义指标迭代函数 |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
//--- 如果没有计算的柱
if(prev_calculated==0)
{
//--- 接收较大时间帧柱形的到达时间
if(!GetTimeData())
return(0);
}
//--- 设置直接索引
ArraySetAsSeries(time,false);
ArraySetAsSeries(high,false);
ArraySetAsSeries(low,false);
ArraySetAsSeries(open,false);
ArraySetAsSeries(close,false);
//--- 启动计算柱形的变量
int start=prev_calculated;
//--- 如果生成柱形,重新计算上面的指标值
if(start!=0 && start==rates_total)
start--;
//--- 循环计算指标值
for(int i=start;i<rates_total;i++)
{
//--- 用空值填充指标缓冲区的i元素
FillIndicatorBuffers(i);
//--- 从InpDateStart日期开始计算柱形
if(time[i]>=InpDateStart)
{
//--- 定义值第一时间显示的持仓
if(ExtStartFlag)
{
//--- 存储最初柱形的数量
ExtStartPos=i;
//--- 定义超过time[i]的较大时间帧的初始日期
while(time[i]>=ExtTimeBuff[ExtCount])
if(ExtCount<ExtSize-1)
ExtCount++;
//--- 改变标识值以便不在这模块再次运行
ExtStartFlag=false;
}
//--- 检查数组中是否有任何元素
if(ExtCount<ExtSize)
{
//--- 等候当前时间帧的值到达较大时间帧的值
if(time[i]>=ExtTimeBuff[ExtCount])
{
//--- 绘制蜡烛图的主要部分(不填写最后和倒数第二柱之间的区域)
FillCandleMain(open,close,high,low,ExtStartPos,i-1,i-2,ExtIndexMax,ExtIndexMin);
//--- 填充蜡烛图末端(最后和倒数第二柱之间的区域)
FillCandleEnd(open,close,high,low,ExtStartPos,i-1,i-1,ExtIndexMax,ExtIndexMin);
//--- 切换初始持仓以绘制下一个蜡烛图
ExtStartPos=i;
//--- 增加数组计数器
ExtCount++;
}
else
continue;
}
else
{
//--- 重置数组的值
ResetLastError();
//--- 接收来自较大时间帧的最后日期
if(CopyTime(Symbol(),InpPeriod,0,1,ExtCurrentTime)==-1)
{
Print("Data copy error, code = ",GetLastError());
return(0);
}
//--- 如果新日期靠后,停止生成蜡烛图
if(ExtCurrentTime[0]>ExtLastTime)
{
//--- 在主要指标缓冲区清空最后和倒数第二柱之间的区域
ClearEndOfBodyMain(i-1);
//--- 使用辅助指标缓冲区填充该区域
FillCandleEnd(open,close,high,low,ExtStartPos,i-1,i-1,ExtIndexMax,ExtIndexMin);
//--- 切换初始持仓以绘制下一个蜡烛图
ExtStartPos=i;
//--- 重置价格方向标识
ExtDirectionFlag=0;
//--- 存储新的最近日期
ExtLastTime=ExtCurrentTime[0];
}
else
{
//--- 生成蜡烛图
FillCandleMain(open,close,high,low,ExtStartPos,i,i,ExtIndexMax,ExtIndexMin);
}
}
}
}
//--- 返回prev_calculated值以便下次调用
return(rates_total);
}
//+------------------------------------------------------------------+
//| 检查指定指标周期的正确性 |
//+------------------------------------------------------------------+
bool CheckPeriod(int current_period,int high_period)
{
//--- 指标周期应该超过显示它的时间帧
if(current_period>=high_period)
{
Print("Error! The value of the indicator period should exceed the value of the current time frame!");
return(false);
}
//--- 如果指标周期是周或月份,周期则是正确的
if(high_period>32768)
return(true);
//--- 转变周期值到分钟
if(high_period>30)
high_period=(high_period-16384)*60;
if(current_period>30)
current_period=(current_period-16384)*60;
//--- 指标周期应该是它显示的时间帧的几倍
if(high_period%current_period!=0)
{
Print("Error! The value of the indicator period should be multiple of the value of the current time frame!");
return(false);
}
//--- 指标周期应该超过它显示的时间帧的3或更多倍
if(high_period/current_period < 3)
{
Print("Error! The indicator period should exceed the current time frame 3 or more times!");
return(false);
}
//--- 指标周期在当前时间帧是正确的
return(true);
}
//+------------------------------------------------------------------+
//| 接收来自较大时间帧的时间数据 |
//+------------------------------------------------------------------+
bool GetTimeData(void)
{
//--- 重置错误的值
ResetLastError();
//--- 复制当前时间的所有数据
if(CopyTime(Symbol(),InpPeriod,InpDateStart,TimeCurrent(),ExtTimeBuff)==-1)
{
//--- 接收错误代码
int code=GetLastError();
//--- 打印错误信息
PrintFormat("Data copy error! %s",code==4401
? "History is still being uploaded!"
: "Code = "+IntegerToString(code));
//--- 返回false,反复尝试下载数据
return(false);
}
//--- 接收数组大小
ExtSize=ArraySize(ExtTimeBuff);
//--- 为数组设置循环指数为零
ExtCount=0;
//--- 在时间帧设置当前蜡烛图位置为零
ExtStartPos=0;
ExtStartFlag=true;
//--- 存储来自较大时间帧的最近时间值
ExtLastTime=ExtTimeBuff[ExtSize-1];
//--- 成功执行
return(true);
}
//+--------------------------------------------------------------------------+
//| 函数形成了蜡烛图的主要部分。根据标识的 |
//| 值,函数定义了要使用哪个数据和数组 |
//| 以便正确显示 |
//+--------------------------------------------------------------------------+
void FormCandleMain(double &body_fst[],double &body_snd[],
double &shadow_fst[],double &shadow_snd[],
const double fst_value,const double snd_value,
const double fst_extremum,const double snd_extremum,
const int start,const int count,const bool flag)
{
//--- 检查标识的值
if(flag)
{
//--- 生成蜡烛图主体
FormMain(body_fst,body_snd,fst_value,snd_value,start,count);
//--- 生成蜡烛图影子
FormMain(shadow_fst,shadow_snd,fst_extremum,snd_extremum,start,count);
}
else
{
//--- 生成蜡烛图主体
FormMain(body_fst,body_snd,snd_value,fst_value,start,count);
//--- 生成蜡烛图影子
FormMain(shadow_fst,shadow_snd,snd_extremum,fst_extremum,start,count);
}
}
//+--------------------------------------------------------------------------------+
//| 函数形成了蜡烛图的末端。根据标识的值, |
//| 函数定义了要使用哪个数据和数组 |
//| 以便正确显示。 |
//+--------------------------------------------------------------------------------+
void FormCandleEnd(double &body_fst[],double &body_snd[],
double &shadow_fst[],double &shadow_snd[],
const double fst_value,const double snd_value,
const double fst_extremum,const double snd_extremum,
const int end,bool &flag)
{
//--- 检查标识的值
if(flag)
{
//--- 生成蜡烛图主体的末端
FormEnd(body_fst,body_snd,fst_value,snd_value,end);
//--- 生成蜡烛图影子的末端
FormEnd(shadow_fst,shadow_snd,fst_extremum,snd_extremum,end);
//--- 改变标识值到相反方向
flag=false;
}
else
{
//--- 生成蜡烛图主体的末端
FormEnd(body_fst,body_snd,snd_value,fst_value,end);
//--- 生成蜡烛图影子的末端
FormEnd(shadow_fst,shadow_snd,snd_extremum,fst_extremum,end);
//--- 改变标识值到相反方向
flag=true;
}
}
//+-------------------------------------------------------------------------------------+
//| 清空蜡烛图末端(最后和倒数第二柱之间的区域) |
//| |
//+-------------------------------------------------------------------------------------+
void ClearEndOfBodyMain(const int ind)
{
ClearCandle(ExtBearBodyFirst,ExtBearBodySecond,ExtBearShadowFirst,ExtBearShadowSecond,ind,1);
ClearCandle(ExtBullBodyFirst,ExtBullBodySecond,ExtBullShadowFirst,ExtBullShadowSecond,ind,1);
}
//+------------------------------------------------------------------+
//| 清空蜡烛图 |
//+------------------------------------------------------------------+
void ClearCandle(double &body_fst[],double &body_snd[],double &shadow_fst[],
double &shadow_snd[],const int start,const int count)
{
//--- 检查
if(count!=0)
{
//--- 以空值填充指标缓冲区
ArrayFill(body_fst,start,count,INDICATOR_EMPTY_VALUE);
ArrayFill(body_snd,start,count,INDICATOR_EMPTY_VALUE);
ArrayFill(shadow_fst,start,count,INDICATOR_EMPTY_VALUE);
ArrayFill(shadow_snd,start,count,INDICATOR_EMPTY_VALUE);
}
}
//+------------------------------------------------------------------+
//| 生成蜡烛图的主要部分 |
//+------------------------------------------------------------------+
void FormMain(double &fst[],double &snd[],const double fst_value,
const double snd_value,const int start,const int count)
{
//--- 检查
if(count!=0)
{
//--- 用值填充指标缓冲区
ArrayFill(fst,start,count,fst_value);
ArrayFill(snd,start,count,snd_value);
}
}
//+------------------------------------------------------------------+
//| 生成蜡烛图末端 |
//+------------------------------------------------------------------+
void FormEnd(double &fst[],double &snd[],const double fst_value,
const double snd_value,const int last)
{
//--- 用值填充指标缓冲区
ArrayFill(fst,last-1,2,fst_value);
ArrayFill(snd,last-1,2,snd_value);
}
//+------------------------------------------------------------------+
//| 通过空值填充指标缓冲区的i元素 |
//+------------------------------------------------------------------+
void FillIndicatorBuffers(const int i)
{
//--- 在指标缓冲区单元设置空值
ExtBearBodyFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBearBodySecond[i]=INDICATOR_EMPTY_VALUE;
ExtBearShadowFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBearShadowSecond[i]=INDICATOR_EMPTY_VALUE;
ExtBearBodyEndFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBearBodyEndSecond[i]=INDICATOR_EMPTY_VALUE;
ExtBearShadowEndFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBearShadowEndSecond[i]=INDICATOR_EMPTY_VALUE;
ExtBullBodyFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBullBodySecond[i]=INDICATOR_EMPTY_VALUE;
ExtBullShadowFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBullShadowSecond[i]=INDICATOR_EMPTY_VALUE;
ExtBullBodyEndFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBullBodyEndSecond[i]=INDICATOR_EMPTY_VALUE;
ExtBullShadowEndFirst[i]=INDICATOR_EMPTY_VALUE;
ExtBullShadowEndSecond[i]=INDICATOR_EMPTY_VALUE;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
# 6.12 ArrayPrint
将 简单类型 或 简单结构 的数组打印输出到日志文本。
void ArrayPrint(
const void& array[], // 打印数组
uint digits=_Digits, // 小数位数
const string separator=NULL, // 结构字段值的分隔符
ulong start=0, // 最初打印元素索引
ulong count=WHOLE_ARRAY, // 打印元素数量
ulong flags=ARRAYPRINT_HEADER|ARRAYPRINT_INDEX|ARRAYPRINT_LIMIT|ARRAYPRINT_ALIGN
);
2
3
4
5
6
7
8
参数
array[]
[in] 简单类型 或 简单结构 的数组。
digits=_Digits
[in] 真实类型的数值保留的小数位数。默认值是 _Digits。
separator=NULL
[in] 结构元素字段值之间的分隔符。默认值NULL表示用空行分隔。这种情况下,使用空格作为分隔符。
start=0
[in] 开始打印数组元素的索引编号。默认从0开始。
count=WHOLE_ARRAY
[in] 打印的数组元素个数。默认为整个数组(count=WHOLE_ARRAY)。
flags=ARRAYPRINT_HEADER|ARRAYPRINT_INDEX|ARRAYPRINT_LIMIT|ARRAYPRINT_ALIGN
[in] 设置输出模式的标帜组合。默认情况下启用所有标帜: ◦ ARRAYPRINT_HEADER —— 打印结构数组标题 ◦ ARRAYPRINT_INDEX —— 在左侧打印索引编号 ◦ ARRAYPRINT_LIMIT —— 仅打印最初100个和最后100个数组元素。此标帜在您只想打印大型数组的一部分的时候使用。 ◦ ARRAYPRINT_ALIGN —— 启用对齐打印值 —— 数字右侧对齐,而行是左侧对齐。 ◦ ARRAYPRINT_DATE —— 打印日期时间的格式,以dd.mm.yyyy格式打印日期 ◦ ARRAYPRINT_MINUTES —— 打印日期时间的格式,以HH:MM格式打印时间 ◦ ARRAYPRINT_SECONDS —— 打印日期时间的格式,以HH:MM:SS格式打印时间
返回值
没有返回值
注意
ArrayPrint() 不会将全部结构数组字段打印到日志 —— 跳过数组和对象指针字段。之所以没有打印这些字段(列)只是为了更方便的展示。如果您需要打印结构中的全部字段,您需要按照所需的格式编写您自己的打印函数。
例如:
//--- 打印最后10 个柱形图的值
MqlRates rates[];
if(CopyRates(_Symbol,_Period,1,10,rates))
{
ArrayPrint(rates);
Print("Check\n[time]\t[open]\t[high]\t[low]\t[close]\t[tick_volume]\t[spread]\t[real_volume]");
for(int i=0;i < 10;i++)
{
PrintFormat("[%d]\t%s\t%G\t%G\t%G\t%G\t%G\t%G\t%I64d\t",i,
TimeToString(rates[i].time,TIME_DATE|TIME_MINUTES|TIME_SECONDS),
rates[i].open,rates[i].high,rates[i].low,rates[i].close,
rates[i].tick_volume,rates[i].spread,rates[i].real_volume);
}
}
else
PrintFormat("CopyRates failed, error code=%d",GetLastError());
//--- 打印示例
/*
[time] [open] [high] [low] [close] [tick_volume] [spread] [real_volume]
[0] 2016.11.09 04:00:00 1.11242 1.12314 1.11187 1.12295 18110 10 17300175000
[1] 2016.11.09 05:00:00 1.12296 1.12825 1.11930 1.12747 17829 9 15632176000
[2] 2016.11.09 06:00:00 1.12747 1.12991 1.12586 1.12744 13458 10 9593492000
[3] 2016.11.09 07:00:00 1.12743 1.12763 1.11988 1.12194 15362 9 12352245000
[4] 2016.11.09 08:00:00 1.12194 1.12262 1.11058 1.11172 16833 9 12961333000
[5] 2016.11.09 09:00:00 1.11173 1.11348 1.10803 1.11052 15933 8 10720384000
[6] 2016.11.09 10:00:00 1.11052 1.11065 1.10289 1.10528 11888 9 8084811000
[7] 2016.11.09 11:00:00 1.10512 1.11041 1.10472 1.10915 7284 10 5087113000
[8] 2016.11.09 12:00:00 1.10915 1.11079 1.10892 1.10904 8710 9 6769629000
[9] 2016.11.09 13:00:00 1.10904 1.10913 1.10223 1.10263 8956 7 7192138000
检查
[time] [open] [high] [low] [close] [tick_volume] [spread] [real_volume]
[0] 2016.11.09 04:00:00 1.11242 1.12314 1.11187 1.12295 18110 10 17300175000
[1] 2016.11.09 05:00:00 1.12296 1.12825 1.1193 1.12747 17829 9 15632176000
[2] 2016.11.09 06:00:00 1.12747 1.12991 1.12586 1.12744 13458 10 9593492000
[3] 2016.11.09 07:00:00 1.12743 1.12763 1.11988 1.12194 15362 9 12352245000
[4] 2016.11.09 08:00:00 1.12194 1.12262 1.11058 1.11172 16833 9 12961333000
[5] 2016.11.09 09:00:00 1.11173 1.11348 1.10803 1.11052 15933 8 10720384000
[6] 2016.11.09 10:00:00 1.11052 1.11065 1.10289 1.10528 11888 9 8084811000
[7] 2016.11.09 11:00:00 1.10512 1.11041 1.10472 1.10915 7284 10 5087113000
[8] 2016.11.09 12:00:00 1.10915 1.11079 1.10892 1.10904 8710 9 6769629000
[9] 2016.11.09 13:00:00 1.10904 1.10913 1.10223 1.10263 8956 7 7192138000
*/
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
相关参考 FileSave, FileLoad
# 6.13 ArrayRange
int ArrayRange(
const void& array[], // 用于检测的数组
int rank_index // 维数
);
2
3
4
参数
array[]
[in] 用于检测的数组
rank_index
[in] 维度的索引编号
返回值
数组中选择维度中的元素个数。
注意
由于索引编号是从0开始的,因此数组维度上的元素个数比维度的索引编号大1。
示例:
void OnStart()
{
//--- 创建一个四维数组
double array[][5][2][4];
//--- 设置维度零的大小
ArrayResize(array,10,10);
//--- 打印输出维度
int temp;
for(int i=0;i<4;i++)
{
//--- 接收i维度大小
temp=ArrayRange(array,i);
//--- 打印
PrintFormat("dim = %d, range = %d",i,temp);
}
//--- 结果
// dim = 0, range = 10
// dim = 1, range = 5
// dim = 2, range = 2
// dim = 3, range = 4
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 6.14 ArrayResize
此函数为数组的第一维度创建新的大小
int ArrayResize(
void& array[], // 用于操作的数组
int new_size, // 新的大小
int reserve_size=0 // 保留大小 (超额的部分)
);
2
3
4
5
参数
array[]
[out] 用于操作的数组
new_size
[in] 第一维度新的大小
reserve_size=0
[in] 分配大小以获取储备。
返回值
如果成功执行,它将返回数组中包含的所有元素的计数,否则,返回-1,并且数组没有调整大小。
如果ArrayResize() 应用于静态数组,时间序列 或 指标缓冲区,数组大小会保持不变 —— 因为这些数组将不会被重新分配。在这种情况下,如果new_size <= ArraySize(数组),函数将只会返回 new_size;否则将会返回 -1值。
注意
该函数只能应用在 动态数组。应该注意的是,您不能将此函数应用于SetIndexBuffer()函数绑定为指标缓冲区的 动态数组,期望更改它的大小。对于指标缓冲区,所有调整大小的操作都由终端的运行时(runtime)子系统执行。
数组中的元素总数不能超过 2147483647个。 在频繁的内存分配中,建议使用第三个参数来设置一个预留空间来减少物理内存分配的数量。所有后续的ArrayResize调用都不会导致物理内存的重新分配,但只会改变保留内存中第一个数组维度的大小。应该记住,第三个参数只在物理内存分配时使用。例如:
ArrayResize(arr,1000,1000); for(int i=1;i<3000;i++) ArrayResize(arr,i,1000);
在这种情况下,内存将被重新分配两次,在进入2000个元素循环之前(数组的大小将被设置为1000),并且第二次使用i等于2000。如果我们不设置第三个参数,将会重新分配2000个元素的物理内存,这会减慢程序的运行速度。
例如:
//+------------------------------------------------------------------+
//| 脚本程序开始函数 |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 计数器
ulong start=GetTickCount();
ulong now;
int count=0;
//--- 用于快速版本维度的数组
double arr[];
ArrayResize(arr,100000,100000);
//--- 检查如何加速内存保留工作的变量
Print("--- Test Fast: ArrayResize(arr,100000,100000)");
for(int i=1;i<=300000;i++)
{
//--- 设置新数组大小指定保存100,000个元素!
ArrayResize(arr,i,100000);
//--- 当到达整十整百的整数时,显示数组大小和花费的时间
if(ArraySize(arr)%100000==0)
{
now=GetTickCount();
count++;
PrintFormat("%d. ArraySize(arr)=%d Time=%d ms",count,ArraySize(arr),(now-start));
start=now;
}
}
//--- 现在显示,无保留内存(即不设置ArrayResize的第三个参数)的版本有多慢
double slow[];
ArrayResize(slow,100000,100000);
//---
count=0;
start=GetTickCount();
Print("---- Test Slow: ArrayResize(slow,100000)");
//---
for(int i=1;i<=300000;i++)
{
//--- 设置新的数组大小,但是无额外储备内存
ArrayResize(slow,i);
//--- 当到达整十整百的整数时,显示数组大小和花费的时间
if(ArraySize(slow)%100000==0)
{
now=GetTickCount();
count++;
PrintFormat("%d. ArraySize(slow)=%d Time=%d ms",count,ArraySize(slow),(now-start));
start=now;
}
}
}
//--- 脚本的示例结果
/*
Test_ArrayResize (EURUSD,H1) --- Test Fast: ArrayResize(arr,100000,100000)
Test_ArrayResize (EURUSD,H1) 1. ArraySize(arr)=100000 Time=0 ms
Test_ArrayResize (EURUSD,H1) 2. ArraySize(arr)=200000 Time=0 ms
Test_ArrayResize (EURUSD,H1) 3. ArraySize(arr)=300000 Time=0 ms
Test_ArrayResize (EURUSD,H1) ---- Test Slow: ArrayResize(slow,100000)
Test_ArrayResize (EURUSD,H1) 1. ArraySize(slow)=100000 Time=0 ms
Test_ArrayResize (EURUSD,H1) 2. ArraySize(slow)=200000 Time=0 ms
Test_ArrayResize (EURUSD,H1) 3. ArraySize(slow)=300000 Time=228511 ms
*/
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# 6.15 ArraySetAsSeries
该函数为选定的一个动态数组的对象设置AS_SERIES标帜,元素将如 时间序列 一样被索引。
bool ArraySetAsSeries(
const void& array[], // 准备操作的数组
bool flag // true表示倒序索引
);
2
3
4
参量
array[]
[in][out] 准备操作的数组
flag
[in] 数组索引编号的方向
返回值
操作成功,返回true,否则返回 false.
注意
不能为 多维数组 或 静态数组(数组方框中的大小在编译时已经指定了明确的数值)设置 AS_SERIES 标帜。时间序列 中的索引不同于普通数组,时间序列的数组中,元素的索引编号是从后往前排序的(从最新的 到 最早的 数据)。
示例:显示K线柱的指标
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots 1
//---- 图表的编号
#property indicator_label1 "Numeration"
#property indicator_type1 DRAW_LINE
#property indicator_color1 CLR_NONE
//--- 指标缓冲区
double NumerationBuffer[];
//+------------------------------------------------------------------+
//| 自定义指标初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 自定义缓冲区绘图
SetIndexBuffer(0,NumerationBuffer,INDICATOR_DATA);
//--- 为类似 时间序列 的缓冲区设置指标
ArraySetAsSeries(NumerationBuffer,true);
//--- 设置数据窗口中显示的精确度
IndicatorSetInteger(INDICATOR_DIGITS,0);
//--- 数组名称的标识符在数据窗口中如何显示
PlotIndexSetString(0,PLOT_LABEL,"Bar #");
//---
return(0);
}
//+------------------------------------------------------------------+
//| 自定义指标循环函数 |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
//--- 保存当前打开的零柱时间
static datetime currentBarTimeOpen=0;
//--- 返回访问数组时间[] - 像时间序列一样
ArraySetAsSeries(time,true);
//--- 如果零柱时间不同于已经保存的
if(currentBarTimeOpen!=time[0])
{
//--- 从当前图表 到 图表最左边 列举所有K线柱
for(int i=rates_total-1;i>=0;i--) NumerationBuffer[i]=i;
currentBarTimeOpen=time[0];
}
//--- 为下次调用返回prev_calculated值
return(rates_total);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
相关参考 访问时间序列 , ArrayGetAsSeries
# 6.16 ArraySize
此函数返回所选数组的元素数量
int ArraySize(
const void& array[] // 检测的数组
);
2
3
参数
array[]
[in] 任意类型的数组
返回值
整数型数值
注意
一维数组,值可以通过 ArraySize 返回,等于 ArrayRange(array,0)
示例:
void OnStart()
{
//--- 创建数组
double one_dim[];
double four_dim[][10][5][2];
//--- 大小
int one_dim_size=25;
int reserve=20;
int four_dim_size=5;
//--- 辅助变量
int size;
//--- 分配内存没有预留空间
ArrayResize(one_dim,one_dim_size);
ArrayResize(four_dim,four_dim_size);
//--- 1. 一维数组
Print("+==========================================================+");
Print("Array sizes:");
Print("1. One-dimensional array");
size=ArraySize(one_dim);
PrintFormat("Zero dimension size = %d, Array size = %d",one_dim_size,size);
//--- 2. 多维数组
Print("2. Multidimensional array");
size=ArraySize(four_dim);
PrintFormat("Zero dimension size = %d, Array size = %d",four_dim_size,size);
//--- 维度大小
int d_1=ArrayRange(four_dim,1);
int d_2=ArrayRange(four_dim,2);
int d_3=ArrayRange(four_dim,3);
Print("Check:");
Print("Zero dimension = Array size / (First dimension * Second dimension * Third dimension)");
PrintFormat("%d = %d / (%d * %d * %d)",size/(d_1*d_2*d_3),size,d_1,d_2,d_3);
//--- 3. 备份内存的一维数组
Print("3. One-dimensional array with memory backup");
//--- 双倍的值
one_dim_size*=2;
//--- 分配预留备份内存
ArrayResize(one_dim,one_dim_size,reserve);
//--- 打印输出大小
size=ArraySize(one_dim);
PrintFormat("Size with backup = %d, Actual array size = %d",one_dim_size+reserve,size);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 6.17 ArraySort
按升序排列多维数字数组中的第一个维度中的值。
bool ArraySort(
void& array[] // 数组排序
);
2
3
参数
array[]
[in][out] 数字数组用于排序
返回值
排序成功返回TRUE,否则是FALSE。
注意
数组通过 AS_SERIES 标签建立,并降序排列。
注释
数组总是按升序排序,而不考虑AS_SERIES标帜。
函数ArraySort 和 ArrayBSearch 接受任何维度的数组为参数。然而,搜索和分类却始终应用于第一(0)维度。
示例:
#property description "The indicator analyzes data for the last month and draws all candlesticks with small"
#property description "and large tick volumes. The tick volume array is sorted out"
#property description "to define such candlesticks. The candlesticks having the volumes comprising the first InpSmallVolume"
#property description "per cent of the array are considered small. The candlesticks having the tick volumes comprising "
#property description "the last InpBigVolume per cent of the array are considered large."
//该指标对上个月的数据进行了分析,并按 报价次数 从小到大绘制了K线柱。K线柱数组被分类,以定义这样的K线。包含该数组中第一个InpSmallVolume的大小的K线柱被认为是小的(包含的报价次数最少)。在该数组中,包含最后一个InpBigVolume百分比的烛台被认为是大的。
//--- 指标设置
#property indicator_chart_window
#property indicator_buffers 5
#property indicator_plots 1
//--- 图
#property indicator_label1 "VolumeFactor"
#property indicator_type1 DRAW_COLOR_CANDLES
#property indicator_color1 clrDodgerBlue,clrOrange
#property indicator_style1 STYLE_SOLID
#property indicator_width1 2
//--- 预定义常量
#define INDICATOR_EMPTY_VALUE 0.0
//--- 输入参数
input int InpSmallVolume=15; // 小型交易量的百分比值 (<50)
input int InpBigVolume=20; // 大型交易量的百分比值 (<50)
//--- 分析起始时间 (将会改变)
datetime ExtStartTime;
//--- 指标缓存区
double ExtOpenBuff[];
double ExtHighBuff[];
double ExtLowBuff[];
double ExtCloseBuff[];
double ExtColorBuff[];
//--- 显示蜡烛图的交易量边界值
long ExtLeftBorder=0;
long ExtRightBorder=0;
//+------------------------------------------------------------------+
//| 接收跳动量的边界值 |
//+------------------------------------------------------------------+
bool GetVolumeBorders(void)
{
//--- 变量
datetime stop_time; // 复制结束时间
long buff[]; // 用于复制的缓冲区
//--- 结束时间是当前时间
stop_time=TimeCurrent();
//--- 起始时间比当前时间早一个月
ExtStartTime=GetStartTime(stop_time);
//--- 接收跳动量的值
ResetLastError();
if(CopyTickVolume(Symbol(),Period(),ExtStartTime,stop_time,buff)==-1)
{
//--- 接收数据失败,返回false启动重新计算的命令
PrintFormat("Failed to receive tick volume values. Error code = %d",GetLastError());
return(false);
}
//--- 计算数组大小
int size=ArraySize(buff);
//--- 分类数组
ArraySort(buff);
//--- 定义跳动量左侧和右侧的边界值
ExtLeftBorder=buff[size*InpSmallVolume/100];
ExtRightBorder=buff[(size-1)*(100-InpBigVolume)/100];
//--- 成功执行
return(true);
}
//+------------------------------------------------------------------+
//| 接收比已过月份少一个月的数据 |
//+------------------------------------------------------------------+
datetime GetStartTime(const datetime stop_time)
{
//--- 转换结束时间到MqlDateTime类型结构变量
MqlDateTime temp;
TimeToStruct(stop_time,temp);
//--- 接收少一个月的数据
if(temp.mon>1)
temp.mon-=1; // 当前月份不是今年的第一个月,因此之前月份减一
else
{
temp.mon=12; // 当前月份是今年的第一个月,因此,前一个月是12月,
temp.year-=1; // 而年份数减一
}
//--- 天数将不会超过28
if(temp.day>28)
temp.day=28;
//--- 返回获得的日期
return(StructToTime(temp));
}
//+------------------------------------------------------------------+
//| 自定义指标初始函数 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 检查是否输入参数满足条件
if(InpSmallVolume<0 || InpSmallVolume>=50 || InpBigVolume<0 || InpBigVolume >= 50)
{
Print("Incorrect input parameters");
return(INIT_PARAMETERS_INCORRECT);
}
//--- 指标缓冲区映射
SetIndexBuffer(0,ExtOpenBuff);
SetIndexBuffer(1,ExtHighBuff);
SetIndexBuffer(2,ExtLowBuff);
SetIndexBuffer(3,ExtCloseBuff);
SetIndexBuffer(4,ExtColorBuff,INDICATOR_COLOR_INDEX);
//--- 设置不被显示的值
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,INDICATOR_EMPTY_VALUE);
//--- 设置指标缓冲区标签
PlotIndexSetString(0,PLOT_LABEL,"Open;High;Low;Close");
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 自定义指标迭代函数 |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
//--- 检查未处理的柱形是否仍然存在
if(prev_calculated<rates_total)
{
//--- 接收交易量右侧和左侧的新边界值
if(!GetVolumeBorders())
return(0);
}
//--- 启动柱形计算的变量
int start=prev_calculated;
//--- 如果在前一个订单号已经计算指标值,那么使用最近的柱形
if(start>0)
start--;
//--- 设置时间序列的直接标引
ArraySetAsSeries(time,false);
ArraySetAsSeries(open,false);
ArraySetAsSeries(high,false);
ArraySetAsSeries(low,false);
ArraySetAsSeries(close,false);
ArraySetAsSeries(tick_volume,false);
//--- 计算指标值的循环
for(int i=start;i<rates_total;i++)
{
//--- 从初始日期填写蜡烛图
if(ExtStartTime<=time[i])
{
//--- 如果值不少于右侧边界,则填写蜡烛图
if(tick_volume[i]>=ExtRightBorder)
{
//--- 接收数据绘制蜡烛图
ExtOpenBuff[i]=open[i];
ExtHighBuff[i]=high[i];
ExtLowBuff[i]=low[i];
ExtCloseBuff[i]=close[i];
//--- 闪蓝色
ExtColorBuff[i]=0;
//--- 继续循环
continue;
}
//--- 如果值不超过左侧边界,则填写蜡烛图
if(tick_volume[i]<=ExtLeftBorder)
{
//--- 接收数据绘制蜡烛图
ExtOpenBuff[i]=open[i];
ExtHighBuff[i]=high[i];
ExtLowBuff[i]=low[i];
ExtCloseBuff[i]=close[i];
//--- 桔色
ExtColorBuff[i]=1;
//--- 继续循环
continue;
}
}
//--- 为计算中不包含的柱设置空值
ExtOpenBuff[i]=INDICATOR_EMPTY_VALUE;
ExtHighBuff[i]=INDICATOR_EMPTY_VALUE;
ExtLowBuff[i]=INDICATOR_EMPTY_VALUE;
ExtCloseBuff[i]=INDICATOR_EMPTY_VALUE;
}
//--- 返回prev_calculated的值以便下次调用
return(rates_total);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
相关参考 ArrayBsearch
# 6.18 ArraySwap
交换相同类型两个动态数组的内容。对于多维数组而言,除了第一个之外,所有维度中的元素数量都应该匹配。
bool ArraySwap(
void& array1[], //第一个数组
void& array2[] //第二个数组
);
2
3
4
参数
array1[]
[in][out] 数值类型的数组。
array2[]
[in][out] 数值类型的数组。
返回值
如果成功返回true,否则返回false。在这种情况下,GetLastError()返回ERR_INVALID_ARRAY错误代码。
注意
该函数会接受相同类型的动态数组和除了第一个维度外的相同维度的数组。对于整数类型,可以忽略符号,例如char==uchar)
例如:
//+------------------------------------------------------------------+
//| 脚本程序起始函数 |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 存储报价的数组
double source_array[][8];
double dest_array[][8];
MqlRates rates[];
//--- 获得当前时间周期最新20个蜡烛图的数据
int copied=CopyRates(NULL,0,0,20,rates);
if(copied<=0)
{
PrintFormat("CopyRates(%s,0,0,20,rates) failed, error=%d",
Symbol(),GetLastError());
return;
}
//--- 为已复制的数据数量设置数组大小
ArrayResize(source_array,copied);
//--- 使用来自rates[]的数据填写rate_array_1[]数组
for(int i=0;i<copied;i++)
{
source_array[i][0]=(double)rates[i].time;
source_array[i][1]=rates[i].open;
source_array[i][2]=rates[i].high;
source_array[i][3]=rates[i].low;
source_array[i][4]=rates[i].close;
source_array[i][5]=(double)rates[i].tick_volume;
source_array[i][6]=(double)rates[i].spread;
source_array[i][7]=(double)rates[i].real_volume;
}
//--- 交换source_array[] 和dest_array[]之间的数据
if(!ArraySwap(source_array,dest_array))
{
PrintFormat("ArraySwap(source_array,rate_array_2) failed, error code=%d",GetLastError());
return;
}
//--- 确保原数组在交换之后变为零
PrintFormat("ArraySwap() done: ArraySize(source_array)=%d",ArraySize(source_array));
//--- 展示dest_array[]目标数组的数据
ArrayPrint(dest_array);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
另见 ArrayCopy,ArrayFill,ArrayRange,ArrayIsDynamic