372 lines
28 KiB
MQL5
372 lines
28 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| PRIC_EA_V1.0_3Kline.mq5 |
|
|
//| PRIC VENTURES |
|
|
//| 耐心 | 理性 | 坚持 | 勇气 |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "PRIC VENTURES"
|
|
#property link "Patience, Rationality, Insistence, Courage"
|
|
#property version "1.0"
|
|
#property description "PRIC_EA_V1.0_3Kline.mq5"
|
|
#property description "魔术号码:202301"
|
|
/*
|
|
(此区域介绍策略)
|
|
【策略名称】
|
|
3根k线策略
|
|
【策略实现】
|
|
|
|
【技术指标】
|
|
|
|
*/
|
|
//▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉
|
|
//+------------------------------------------------------------------+------------------------------------------------------------------+
|
|
//| ☀☀☀此区域↓↓↓→导入类/头文件★█ ▼▼▼▼▼▼导入类/头文件▼▼▼▼▼▼
|
|
//+------------------------------------------------------------------+------------------------------------------------------------------+
|
|
#include <PRIC_Class\PRIC_C_OrderSystem_V1.0.mqh>
|
|
|
|
//▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉
|
|
//+------------------------------------------------------------------+------------------------------------------------------------------+
|
|
//| 此区域↓↓↓→定义Input变量★█ ▼▼▼▼▼▼定义Input变量▼▼▼▼▼▼
|
|
//+------------------------------------------------------------------+------------------------------------------------------------------+
|
|
input int MA1=5;
|
|
input ENUM_MA_METHOD MAType1 = MODE_SMA;
|
|
input int MA2=50;
|
|
input ENUM_MA_METHOD MAType2 = MODE_SMA;
|
|
input int Slippage = 50; // 滑点
|
|
input double LotSize = 0.1; // 下单量
|
|
//▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉
|
|
//+------------------------------------------------------------------+------------------------------------------------------------------+
|
|
//| 此区域↓↓↓→定义全局变量★█ ▼▼▼▼▼▼定义全局变量▼▼▼▼▼▼
|
|
//+------------------------------------------------------------------+------------------------------------------------------------------+
|
|
#define def_MagicValue 202301 //此处设置Magic 魔术单号 的数值(一个策略一个编号)
|
|
|
|
enum eChecker {None_Open, Long_Open, Short_Open};
|
|
eChecker m_Check;
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
|
|
double Lowest = 0;
|
|
double Highest = 0;
|
|
int sl_lastBar = 0;
|
|
|
|
double MA1Buffer[];
|
|
double MA2Buffer[];
|
|
|
|
int MA1Handle;
|
|
int MA2Handle;
|
|
|
|
int count;
|
|
//▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉
|
|
//+------------------------------------------------------------------+------------------------------------------------------------------+
|
|
//| 此区域↓↓↓→定义结构★█ ▼▼▼▼▼▼定义结构▼▼▼▼▼▼
|
|
//+------------------------------------------------------------------+------------------------------------------------------------------+
|
|
|
|
//--- 本策略不涉及
|
|
|
|
//▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉
|
|
//+------------------------------------------------------------------+------------------------------------------------------------------+
|
|
//| 此区域↓↓↓→声明对象/变量★█ ▼▼▼▼▼▼声明对象/变量▼▼▼▼▼▼
|
|
//+------------------------------------------------------------------+------------------------------------------------------------------+
|
|
COrderSystem *order;
|
|
//▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+------------------------------------------------------------------+
|
|
//| OnInit() 函数是 初始化 事件处理程序。★█ ▼▼▼▼▼▼OnInit()▼▼▼▼▼▼
|
|
//+------------------------------------------------------------------+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
//+------------------------------------------------------------------------------------------------------------------------+
|
|
//| 此处↓↓↓→定义指标句柄/初始启动变量★★★★★★〓 ★★★★★★编写策略★★★★★★
|
|
//+------------------------------------------------------------------------------------------------------------------------+
|
|
order = new COrderSystem(def_MagicValue);
|
|
|
|
m_Check = None_Open;
|
|
|
|
count = 0;
|
|
|
|
|
|
// 获取MA指标句柄,适应当前周期
|
|
MA1Handle = iMA(Symbol(), Period(), MA1, 0, MAType1, PRICE_CLOSE);
|
|
MA2Handle = iMA(Symbol(), Period(), MA2, 0, MAType2, PRICE_CLOSE);
|
|
if(MA1Handle == INVALID_HANDLE || MA2Handle == INVALID_HANDLE)
|
|
{
|
|
Print("无法创建MA指标: ", GetLastError());
|
|
}
|
|
|
|
// 定义缓冲区
|
|
|
|
|
|
ArraySetAsSeries(MA1Buffer, true);
|
|
ArraySetAsSeries(MA2Buffer, true);
|
|
|
|
|
|
|
|
//---
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
//+------------------------------------------------------------------+------------------------------------------------------------------+
|
|
//| OnDeinit() 函数称为失败初始化,是初始化失败事件处理程序。★█ ▼▼▼▼▼▼OnDeinit()▼▼▼▼▼▼
|
|
//+------------------------------------------------------------------+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
//--- 释放分配的内存,防止内存泄露
|
|
delete order;
|
|
//--- destroy timer
|
|
EventKillTimer();
|
|
|
|
}
|
|
//+------------------------------------------------------------------+------------------------------------------------------------------+
|
|
//| OnTick() 函数是图表驱动,每当图表上Tick跳动时运行。★█ ▼▼▼▼▼▼OnTick()▼▼▼▼▼▼
|
|
//+------------------------------------------------------------------+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
|
|
double Ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
|
|
double Bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
|
|
|
|
|
|
// 从MA指标中复制数据
|
|
if(CopyBuffer(MA1Handle, 0, 0, 3, MA1Buffer) <= 0 ||
|
|
CopyBuffer(MA2Handle, 0, 0, 3, MA2Buffer) <= 0)
|
|
{
|
|
Print("CopyBuffer 失败: ", GetLastError());
|
|
return;
|
|
}
|
|
|
|
// 获取当前和前一根K线的
|
|
double MA1_1 = MA1Buffer[1]; // 当前K线
|
|
double MA1_2 = MA1Buffer[2]; // 前一根K线
|
|
double MA2_1 = MA2Buffer[1];
|
|
double MA2_2 = MA2Buffer[2];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(m_Check == None_Open)
|
|
{
|
|
if(MA1_1 > MA2_1)
|
|
{
|
|
order.MarketOpen(Symbol(), ORDER_TYPE_BUY, LotSize, Ask, Ask - 400*Point(), 0, "202301_Buy");
|
|
Print("正常开多!");
|
|
m_Check = Long_Open;
|
|
Print("仓位状态【多】");
|
|
Print("【开多仓】后信号【", m_Check, "】");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int sl_currBar = iBars(Symbol(),Period());
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
//+------------------------------------------------------------------+------------------------------------------------------------------+
|
|
// Start - 解决平仓后很长一段时间不开单————如下:
|
|
/*
|
|
【说明】:
|
|
为什么一段时间不能开单后,突然又能开单了,原因如下:
|
|
因为在【196行】极值判断平仓的代码部分,要先if(m_Check == None_Open)为true,再if(sl_currBar > sl_lastBar)为true,才会运行
|
|
get3KlineExtre();获取极值;因为m_Check因【固定止损】平仓后未被重置,仍保持Long_Open,所以极值值判断平仓的代码,每更新1根
|
|
K线后仍会运行一次,且因为1根K线只运行1次,那在if(Bid < Lowest)中,Bid的价格每根K线也只获取1次,且在K线刚形成时获取,Bid
|
|
价格就会出现以下情况:
|
|
1、当Bid获取时,K线的Open价格在上一【低值】上方,那当前K线的if(Bid < Lowest)就会为false,不会进入平仓并重置信号的代码,导致一段时间不开单;
|
|
2、当Bid获取时,K线的Open价格在上一【低值】下方,那当前K线的if(Bid < Lowest)就会为true,进入平仓部分的代码:
|
|
(1)进入平仓部分代码后,因为MarketClose()是一个bool型函数,只要传递的参数格式正确,就会被正常执行,然后返回true
|
|
或false,这也是系统的MqlRequest特性决定的。
|
|
(2)所以当新K线的Open价格在上一【低值】下方时,因为仓位早就被【固定止损】平掉了,那么
|
|
MarketClose()内运行PositionSelect(Symbol()) ? PositionGetInteger(POSITION_TICKET): (long)0时,自然找不到仓位返回了0,
|
|
接着该函数仍然会被正确执行发送,然后执行接下来的m_Check = None_Open;重置信号,就又突然可以开单了。
|
|
|
|
【解决办法】:因为获取极值更新是为了平仓用,其前提是有仓位存在,才有执行这段代码的必要,所以在信号检测后,加一个仓位检测就解决了上述问题。
|
|
当信号检测if(m_Check == Long_Open)为true,但接着却检测不到仓位,就说明仓位被【固定止损】平了,为其加个else,执行信号重置。
|
|
|
|
|
|
// End - 解决平仓后很长一段时间不开单————如上 */
|
|
//+------------------------------------------------------------------+------------------------------------------------------------------+
|
|
|
|
|
|
if(m_Check == Long_Open)
|
|
{
|
|
if(PositionSelect(_Symbol)) //【新增代码】仓位检测。因为这里用过PositionSelect()了,后面MarketClose()里就不需要了,已删除。
|
|
{
|
|
if(sl_currBar > sl_lastBar)
|
|
{
|
|
sl_lastBar = sl_currBar;
|
|
get3KlineExtre();
|
|
|
|
if(Bid < Lowest)
|
|
{
|
|
order.MarketClose(PositionGetInteger(POSITION_TICKET), Slippage);
|
|
|
|
Print("多单因【小于Lowest】关闭!"); //【代码变动】调试用
|
|
Print("平仓时 Lowest 的值为:", Lowest);
|
|
m_Check = None_Open;
|
|
Print("【平仓】后信号【", m_Check, "】"); //【新增代码】调试用
|
|
Lowest = 0; //【新增代码】平仓后初始化极值
|
|
|
|
}
|
|
}
|
|
}
|
|
else //【新增代码】当信号为Long_Open仓位却不存在时,重置信号
|
|
{
|
|
m_Check = None_Open;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void OnTimer()
|
|
{
|
|
|
|
} //OnTimer尾括号
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
inline eChecker CheckPositionsStatus(void)
|
|
{
|
|
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
|
{
|
|
if(PositionGetTicket(i)>0)
|
|
{
|
|
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
|
|
{
|
|
return Long_Open;
|
|
}
|
|
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
|
|
{
|
|
return Short_Open;
|
|
}
|
|
}
|
|
if(PositionGetTicket(i)==0)
|
|
{
|
|
return None_Open;
|
|
}
|
|
}
|
|
return None_Open;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
|
|
|
|
|
|
|
//--- 获取3根K线顶底形态函数:顶-暮星-eveningStar;底-晨星-morningStar
|
|
int get3KlineExtre()
|
|
{
|
|
|
|
MqlRates klineArray[];
|
|
ArraySetAsSeries(klineArray, true);
|
|
int mqlrates_date = CopyRates(_Symbol, PERIOD_CURRENT, 0, 4, klineArray);
|
|
|
|
//--- 获取判断K线形态所需的数据
|
|
datetime klineOpenTime = klineArray[2].time; //【代码变动】索引改为2,用于绘制低值的指示箭头
|
|
double open1 = klineArray[1].open;
|
|
double open2 = klineArray[2].open;
|
|
double open3 = klineArray[3].open;
|
|
double high1 = klineArray[1].high;
|
|
double high2 = klineArray[2].high;
|
|
double high3 = klineArray[3].high;
|
|
double low1 = klineArray[1].low;
|
|
double low2 = klineArray[2].low;
|
|
double low3 = klineArray[3].low;
|
|
double close1 = klineArray[1].close;
|
|
double close2 = klineArray[2].close;
|
|
double close3 = klineArray[3].close;
|
|
long vol1 = klineArray[1].tick_volume;
|
|
long vol2 = klineArray[2].tick_volume;
|
|
long vol3 = klineArray[3].tick_volume;
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
if((low1 > low2) && (low3 > low2))
|
|
{
|
|
if((open1 < close1) && (open2 < close2))
|
|
{
|
|
Lowest = low2;
|
|
count++; //【新增代码】用于绘制低值的指示文本
|
|
string text0 = (string)count; //【新增代码】用于绘制低值的指示文本
|
|
string text1 = (string)Lowest; //【新增代码】用于绘制低值的指示文本
|
|
createObj(klineOpenTime, Lowest, 217, clrYellow, "第" + text0 + "次更新低值" + text1); //【新增代码】用于绘制低值的指示文本
|
|
Print("极小值更新:【", Lowest, "】"); //【新增代码】用于调试
|
|
|
|
return -1;
|
|
}
|
|
|
|
//--- 判断顶部形态:暮星-Evening Star
|
|
//--- 如果倒数第2根 看跌
|
|
if((high1 < high2) && (high3 < high2))
|
|
{
|
|
if((open1 > close1) && (open2 > close2))
|
|
{
|
|
Highest = high2;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
//--- 返回0代表3根k线未形成顶、底结构
|
|
return 0;
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//【新增函数】用于调用以在图表上绘制出,检测到的符合条件的低值。这时一个通用函数,可根据需要定制修改
|
|
//+------------------------------------------------------------------+
|
|
//--- 在图表创建顶、底形态文字标识函数
|
|
void createObj(datetime klineOpenTime, double price, int arrawCode,
|
|
color clr, string txt)
|
|
{
|
|
//--- 设置图表标识名称,可根据需要自定义,这里留空便于在下方设置
|
|
string objName = " ";
|
|
//--- 创建字符串信息,并存储在objName中
|
|
StringConcatenate(objName, "信号@", klineOpenTime, "在",
|
|
DoubleToString(price, _Digits), "(",
|
|
arrawCode, ")");
|
|
//--- 在图表上创建一个箭头物件,并判断,如果返回true创建成功
|
|
if(ObjectCreate(0, objName, OBJ_ARROW, 0, klineOpenTime, price))
|
|
{
|
|
//--- 箭头创建成功,为其设置箭头样式和颜色
|
|
ObjectSetInteger(0, objName, OBJPROP_ARROWCODE, arrawCode);
|
|
ObjectSetInteger(0, objName, OBJPROP_COLOR, clr);
|
|
//--- 判断是晨星/暮星,决定箭头放置的位置
|
|
if(clr == clrYellow)
|
|
{
|
|
//--- 晨星,箭头放置在倒数第2根k线的最低价处
|
|
ObjectSetInteger(0, objName, OBJPROP_ANCHOR, ANCHOR_TOP);
|
|
}
|
|
if(clr == clrRed)
|
|
{
|
|
//--- 暮星,箭头放置在倒数第2根k线的最高价处
|
|
ObjectSetInteger(0, objName, OBJPROP_ANCHOR, ANCHOR_BOTTOM);
|
|
}
|
|
|
|
}
|
|
//--- 创建一个新的物件名字,用于创建文本物件时指向
|
|
string klineName = objName + txt;
|
|
//--- 在箭头旁再创建一个文本物件,用于解释箭头的含义
|
|
if(ObjectCreate(0, klineName, OBJ_TEXT, 0, klineOpenTime, price))
|
|
{
|
|
//--- 文本物件创建成功,为其设置颜色和文本内容
|
|
ObjectSetString(0, klineName, OBJPROP_TEXT, " " + txt);
|
|
ObjectSetInteger(0, klineName, OBJPROP_COLOR, clr);
|
|
}
|
|
}
|
|
|
|
|