| 64 |
MQL5运行TensorFlow训练出来的模型 |
<p>1、本篇笔记也是在MQL5网上看到大佬的笔记作的修改<br />2、利用Tensorflow训练,MQL5运行。<br />3、模型训练的方式,已经在另一篇文章记录</p>
<pre class=""><code class="language-cpp hljs">//+------------------------------------------------------------------+
//| TimelessAI.mq5 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Timeless"
#property link "https://www.mql5.com"
#property version "1.00"
#include <Trade\Trade.mqh>
input double InpLots = 1.0; // Lots amount to open position
input bool InpUseStops = true; // Use stops in trading
input int InpTakeProfit = 500; // TakeProfit level
input int InpStopLoss = 500; // StopLoss level
#resource "model.eurusd.H1.120.onnx" as uchar ExtModel[]
//SAMPLE_SIZE: 定义每次预测使用的历史数据的大小(120个时间点)。
#define SAMPLE_SIZE 120
//ExtHandle: 保存ONNX模型的句柄。
//ExtPredictedClass: 保存模型预测的结果(价格上升、持平或下降)。
//ExtNextBar、ExtNextDay: 用于管理图表的下一根K线和日期。
//ExtMin、ExtMax: 保存价格的最小值和最大值,用于归一化。
//ExtTrade: 用于交易操作的CTrade对象。
long ExtHandle = INVALID_HANDLE;
int ExtPredictedClass = -1;
datetime ExtNextBar = 0;
datetime ExtNextDay = 0;
float ExtMin = 0.0;
float ExtMax = 0.0;
CTrade ExtTrade;
//--- price movement prediction
#define PRICE_UP 0
#define PRICE_SAME 1
#define PRICE_DOWN 2
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit() {
//---
if(_Symbol != "EURUSD" || _Period != PERIOD_H1) {
Print("model must work with EURUSD,H1");
return(INIT_FAILED);
}
//--- 加载ONNX模型并获取句柄ExtHandle
ExtHandle = OnnxCreateFromBuffer(ExtModel, ONNX_DEFAULT);
if(ExtHandle == INVALID_HANDLE) {
Print("OnnxCreateFromBuffer error ", GetLastError());
return(INIT_FAILED);
}
// 由于并非输入张量中定义的所有大小,我们必须显式设置它们
// 第一个索引-批量大小,第二个索引-系列大小,第三个索引-序列号(仅关闭)
// 设置ONNX模型的输入和输出维度。输入维度为{1, SAMPLE_SIZE, 1},
// 表示批量大小为1,输入时间序列长度为120,特征数为1(收盘价)。
const long input_shape[] = {1, SAMPLE_SIZE, 1};
if(!OnnxSetInputShape(ExtHandle, ONNX_DEFAULT, input_shape)) {
Print("OnnxSetInputShape error ", GetLastError());
return(INIT_FAILED);
}
//---由于并非输出张量中定义的所有大小,我们必须显式设置它们
//---第一个索引-批大小,必须与输入张量的批大小匹配
//---第二个指数-预测价格的数量(我们只预测收盘价)
//输出维度为{1, 1},表示模型输出1个预测值。
const long output_shape[] = {1, 1};
if(!OnnxSetOutputShape(ExtHandle, 0, output_shape)) {
Print("OnnxSetOutputShape error ", GetLastError());
return(INIT_FAILED);
}
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
//---
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick() {
// 返回当前服务器的时间(以秒为单位),
//ExtNextDay 是存储下一个新的一天的时间戳(通常基于午夜)。
//这行代码判断当前时间是否超过或等于下一天的时间点。
if(TimeCurrent() >= ExtNextDay) {
GetMinMax();
//--- set next day time
ExtNextDay = TimeCurrent();
ExtNextDay -= ExtNextDay % PeriodSeconds(PERIOD_D1);
ExtNextDay += PeriodSeconds(PERIOD_D1);
}
//--- check new bar
if(TimeCurrent() < ExtNextBar)
return;
//如果当前时间已经超过了 ExtNextBar,则更新 ExtNextBar 为下一个 K 线的时间:
//PeriodSeconds() 获取当前图表周期的秒数(例如,PeriodSeconds() 如果是 M1 则返回 60 秒,M5 则返回 300 秒等)。
//通过对当前时间取模并加上周期秒数,调整 ExtNextBar 为下一个完整的 K 线开始时间。
ExtNextBar = TimeCurrent();
ExtNextBar -= ExtNextBar % PeriodSeconds();
ExtNextBar += PeriodSeconds();
float close = (float)iClose(_Symbol, _Period, 0);
// 如果 ExtMin(当天最低价)大于当前的收盘价 close,则更新 ExtMin 为当前的 close。这行代码在每次 OnTick 被调用时检查并更新当天的最低价
if(ExtMin > close)
ExtMin = close;
if(ExtMax < close)
ExtMax = close;
//--- predict next price
PredictPrice();
//--- check trading according to prediction
if(ExtPredictedClass >= 0)
if(PositionSelect(_Symbol))
CheckForClose();
else
CheckForOpen();
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Get minimal and maximal Close for last 120 days |
//+------------------------------------------------------------------+
//该函数获取过去120天(SAMPLE_SIZE)的日线收盘价,并计算其中的最小值和最大值,用于后续的归一化处理。
void GetMinMax(void) {
//这里定义了一个名为 close 的变量,类型为 vectorf。
//vectorf 是 MQL5 中的一个数据结构,用来存储浮动的数据序列,在这里用于存储一段时间内的收盘价数据。
//vectorf 是一个一维数组,通常用于存储单一类型的数值数据,如收盘价、开盘价等。
//MqlRates 是一个结构体,表示单根K线的数据,包含了开盘价、最高价、最低价、收盘价等多个字段。
vectorf close;
//获取最120根K线的收盘价
close.CopyRates(_Symbol, PERIOD_D1, COPY_RATES_CLOSE, 0, SAMPLE_SIZE);
//将过去120根K线的收盘价的最低价放在ExtMin里
ExtMin = close.Min();
//将过去120根K线的收盘价的最高价放在ExtMax里
ExtMax = close.Max();
}
//+------------------------------------------------------------------+
//| Predict next price |
//+------------------------------------------------------------------+
//该函数用于获取预测的价格方向:
// 首先从图表获取过去120个时间点的收盘价,并进行归一化处理(使用最小值和最大值)。
// 然后将归一化的价格数据输入到ONNX模型中,运行推理得到预测值。
// 根据预测值与当前收盘价的差异,确定预测的价格趋势:
// PRICE_SAME:表示预测价格与当前价格相同。
// PRICE_UP:表示预测价格上涨。
// PRICE_DOWN:表示预测价格下跌。
void PredictPrice(void) {
//这行代码定义了一个静态的 vectorf 类型变量 output_data,大小为 1。vectorf 用于存储浮动类型的数值数据,
//这里用来存储预测的结果。
static vectorf output_data(1); // vector to get result
//这行定义了另一个静态的 vectorf 类型变量 x_norm,大小为 SAMPLE_SIZE。
//它用于存储经过归一化处理的价格数据。
static vectorf x_norm(SAMPLE_SIZE); // vector for prices normalize
//检查是否可以进行归一化。如果 ExtMin (最小值)大于或等于 ExtMax (最大值),则无法归一化。
//在这种情况下,ExtPredictedClass 被设置为 -1(表示错误状态),并且函数直接返回,不进行进一步操作。
if(ExtMin >= ExtMax) {
ExtPredictedClass = -1;
return;
}
//使用 CopyRates 函数从图表请求历史数据。具体参数:
//_Symbol 表示当前交易品种(例如 EURUSD)。
//_Period 表示时间周期(例如 D1)。
//COPY_RATES_CLOSE 表示只复制收盘价数据。
//1 表示从最近的时间点开始请求数据。
//SAMPLE_SIZE 表示请求的数据条数。
//如果请求失败,ExtPredictedClass 被设置为 -1,表示发生错误,然后函数返回。
if(!x_norm.CopyRates(_Symbol, _Period, COPY_RATES_CLOSE, 1, SAMPLE_SIZE)) {
ExtPredictedClass = -1;
return;
}
//---
//该行获取最后一根 K 线的收盘价。因为数据被存储在 x_norm 中,x_norm[SAMPLE_SIZE - 1] 表示数组中的最后一个元素,即最近的收盘价。
float last_close = x_norm[SAMPLE_SIZE - 1];
//这两行代码将价格数据进行归一化处理:
//x_norm -= ExtMin;:将数据中的每个元素减去最小值 ExtMin,以确保数据从 0 开始。
//x_norm /= (ExtMax - ExtMin);:然后将数据除以 (ExtMax - ExtMin),使数据范围变为 0 到 1。这样就完成了归一化。
x_norm -= ExtMin;
x_norm /= (ExtMax - ExtMin);
//OnnxRun 是一个函数,用于通过 ONNX 模型进行推理。具体参数:
//ExtHandle 是 ONNX 模型的句柄。
//ONNX_NO_CONVERSION 表示不进行数据类型转换。
//x_norm 是归一化后的价格数据,作为输入传入。
//output_data 用于存储推理的输出结果。
//如果推理失败,ExtPredictedClass 被设置为 -1,表示错误状态,函数直接返回。
if(!OnnxRun(ExtHandle, ONNX_NO_CONVERSION, x_norm, output_data)) {
ExtPredictedClass = -1;
return;
}
//这行代码将预测的输出值从 0 到 1 的范围反归一化到实际价格范围。
// output_data[0] 是 ONNX 模型输出的归一化预测结果。
// (ExtMax - ExtMin) 将归一化结果还原为实际的价格范围。
// + ExtMin 是为了将结果偏移回到正确的价格区间。
float predicted = output_data[0] * (ExtMax - ExtMin) + ExtMin;
//计算预测的价格(predicted)与最后的收盘价(last_close)之间的差异delta。
//如果差异为负,表示预测价格低于当前收盘价;如果差异为正,表示预测价格高于当前收盘价。
float delta = last_close - predicted;
//如果 delta 的绝对值非常小(即价格变化几乎为 0),那么预测的价格与当前收盘价几乎相同。
//此时,ExtPredictedClass 被设置为 PRICE_SAME,表示价格保持不变。
if(fabs(delta) <= 0.003)
ExtPredictedClass = PRICE_SAME;
else {
if(delta < 0)
ExtPredictedClass = PRICE_UP;
else
ExtPredictedClass = PRICE_DOWN;
}
}
//+------------------------------------------------------------------+
//| Check for open position conditions |
//+------------------------------------------------------------------+
//根据预测的价格趋势(上涨或下跌),判断建仓信号:
//如果预测价格上涨(PRICE_UP),则选择买入。
//如果预测价格下跌(PRICE_DOWN),则选择卖出。
//根据输入参数设置止损和止盈,并在允许交易的情况下建仓。
void CheckForOpen(void) {
//定义一个变量 signal,类型为 ENUM_ORDER_TYPE,用于表示订单类型(买单或卖单)。初始化为 WRONG_VALUE,表示没有有效的信号。
ENUM_ORDER_TYPE signal = WRONG_VALUE;
//--- check signals
if(ExtPredictedClass == PRICE_DOWN)
signal = ORDER_TYPE_SELL; // sell condition
else {
if(ExtPredictedClass == PRICE_UP)
signal = ORDER_TYPE_BUY; // buy condition
}
//检查 signal 是否有效(即不等于 WRONG_VALUE),并且检查终端是否允许交易(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) 返回是否可以进行交易)。
if(signal != WRONG_VALUE && TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) {
double price, sl = 0, tp = 0;
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if(signal == ORDER_TYPE_SELL) {
price = bid;
// 如果启用了止损止盈(InpUseStops),则根据当前卖价 (bid) 和止损、止盈的参数进行计算:
// sl = NormalizeDouble(bid + InpStopLoss * _Point, _Digits);:计算止损价格(卖价加上止损距离),并将其规范化为适合当前交易品种的价格精度。
// tp = NormalizeDouble(ask - InpTakeProfit * _Point, _Digits);:计算止盈价格(买价减去止盈距离),并规范化为适合的精度。
if(InpUseStops) {
sl = NormalizeDouble(bid + InpStopLoss * _Point, _Digits);
tp = NormalizeDouble(ask - InpTakeProfit * _Point, _Digits);
}
} else {
price = ask;
if(InpUseStops) {
sl = NormalizeDouble(ask - InpStopLoss * _Point, _Digits);
tp = NormalizeDouble(bid + InpTakeProfit * _Point, _Digits);
}
}
ExtTrade.PositionOpen(_Symbol, signal, InpLots, price, sl, tp);
}
}
//+------------------------------------------------------------------+
//| 平仓条件判断 |
//| 如果设置了止损和止盈,函数会直接返回。 |
//| 如果没有设置止损和止盈,检查当前持仓的类型: |
//| 如果是买入仓位且预测价格下跌,则平仓并反向开仓。 |
//| 如果是卖出仓位且预测价格上涨,则平仓并反向开仓。 |
//+------------------------------------------------------------------+
void CheckForClose(void) {
//这行代码检查是否启用了止损(InpUseStops)。
//如果启用了止损,函数将直接返回,不会继续执行其他的平仓操作。这意味着止损机制优先于其他信号。
if(InpUseStops)
return;
//定义一个布尔变量 bsignal,初始化为 false。这个变量用来表示是否存在需要平仓的信号。
bool bsignal = false;
//使用 PositionGetInteger(POSITION_TYPE) 获取当前持仓的类型,返回值存储在 type 变量中:
// POSITION_TYPE_BUY 表示当前持仓为买单。
// POSITION_TYPE_SELL 表示当前持仓为卖单。
long type = PositionGetInteger(POSITION_TYPE);
//如果当前持仓为买单 (POSITION_TYPE_BUY),并且 ExtPredictedClass 为 PRICE_DOWN(即预测价格将下跌),则将 bsignal 设置为 true,表示需要平仓。
if(type == POSITION_TYPE_BUY && ExtPredictedClass == PRICE_DOWN)
bsignal = true;
//如果当前持仓为卖单 (POSITION_TYPE_SELL),并且 ExtPredictedClass 为 PRICE_UP(即预测价格将上涨),则将 bsignal 设置为 true,表示需要平仓
if(type == POSITION_TYPE_SELL && ExtPredictedClass == PRICE_UP)
bsignal = true;
//如果 bsignal 为 true(即需要平仓)并且终端允许交易(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) 返回 true),则执行平仓操作。
if(bsignal && TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) {
//调用 ExtTrade.PositionClose 函数平掉当前持仓,_Symbol 表示当前的交易品种,3 表示平仓的魔术数字,通常用于标识特定的订单。
ExtTrade.PositionClose(_Symbol, 3);
//--- open opposite
CheckForOpen();
}
}
//+------------------------------------------------------------------+
</code></pre> |
1 |
50 |
1 |
3/6/26, 7:47 PM |
3/6/26, 7:47 PM |
View Edit Delete |
| 65 |
MQL5 自己的编写的常用函数 |
<p>自己以前写的代码,用来判断一些常用的事件包括</p>
<p>1、检查是否有新的K线出现</p>
<p>2、限制小数位数(部分品种历史数据中有超过图表正常值)</p>
<p>3、检测保证金是否充足</p>
<p>4、是否达到订单上限</p>
<p>5、下单</p>
<p>6、追踪止损</p>
<p>7、是否在允许的交易时间范围</p>
<p>8、单边总共有多少亏损订单(这个一般马丁用,实际情况几乎不用)</p>
<pre class=""><code class="language-cpp hljs">//+------------------------------------------------------------------+
//| 检查是否有新K线 |
//+------------------------------------------------------------------+
bool IsNewBar(string symbol, ENUM_TIMEFRAMES timeframe) {
// 获取当前时间周期的最新K线时间
datetime currentBarTime = iTime(symbol, timeframe, 0);
// 如果当前K线时间与上次记录的不同,说明有新K线生成
if (currentBarTime > lastBarTimes) {
lastBarTimes = currentBarTime; // 更新最后K线时间
return true; // 返回新K线标志
}
return false; // 没有新K线
}
//+------------------------------------------------------------------+
//| 限制小数位数 |
//+------------------------------------------------------------------+
double RoundToNDecimalPlaces(double value, int decimalPlaces) {
double factor = MathPow(10, decimalPlaces);
value = MathRound(value * factor) / factor;
return value;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| 检测保证金是否充足 |
//+------------------------------------------------------------------+
bool CheckMoneyForTrade(string symb, double lots, ENUM_ORDER_TYPE type) {
//--- Getting the opening price
MqlTick mqltick;
SymbolInfoTick(symb, mqltick);
double price = mqltick.ask;
if(type == ORDER_TYPE_SELL)
price = mqltick.bid;
//--- values of the required and free margin
double margin, free_margin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
//--- call of the checking function
if(!OrderCalcMargin(type, symb, lots, price, margin)) {
//--- something went wrong, report and return false
Print("Error in ", __FUNCTION__, " code=", GetLastError());
return(false);
}
//--- if there are insufficient funds to perform the operation\
if(margin > free_margin) {
//--- report the error and return false
Print("Not enough money for ", EnumToString(type), " ", lots, " ", symb, " Error code=", GetLastError());
return(false);
}
//--- checking successful
return(true);
}
//+------------------------------------------------------------------+
//| 是否达到订单上限 |
//+------------------------------------------------------------------+
bool IsLimitOrder(string symbol,string type,string comment) {
CTrade trade;
int totalPositions = PositionsTotal();
int count = 0;
for(int i = 0; i < totalPositions; i++) {
ulong ticket = PositionGetTicket(i);
// 如果成功选择持仓订单
if(PositionSelectByTicket(ticket)) {
string order_symbol = PositionGetString(POSITION_SYMBOL);
string order_comment = PositionGetString(POSITION_COMMENT);
// 获取订单类型
ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
string order_type = (positionType == POSITION_TYPE_BUY) ? "Buy" : "Sell";
if(symbol == order_symbol && type == order_type && comment == order_comment) {
count++;
}
}
}
if(count >= iOrderLimit) {
return false;
}
return true;
}
//+------------------------------------------------------------------+
////+------------------------------------------------------------------+
////| 单边共有多少损单 |
////+------------------------------------------------------------------+
//int FindNearestLossCount(string symbol,ENUM_TIMEFRAMES timeframe, string order_type) {
// HistorySelect(TimeLocal() - 2 * 24 * 3600, TimeCurrent());
// int total = HistoryDealsTotal();
// int count = 0;
// bool is_break = false;
// //Print(total+"订单总数");
// for(int i=total-1; i>=0; i--) {
//
// ulong in_order_ticket = HistoryDealGetTicket(i);
// ENUM_DEAL_ENTRY in_order_entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(in_order_ticket, DEAL_ENTRY);
// //入方向订单(开仓)
// if(in_order_entry == DEAL_ENTRY_IN) {
// ulong in_order_positionId = HistoryDealGetInteger(in_order_ticket, DEAL_POSITION_ID);
// string in_order_symbol = HistoryDealGetString(in_order_ticket, DEAL_SYMBOL);
// int digits = SymbolInfoInteger(in_order_symbol, SYMBOL_DIGITS);
// string in_order_type = (HistoryDealGetInteger(in_order_ticket, DEAL_TYPE) == DEAL_TYPE_BUY) ? "Buy" : "Sell";
// double in_order_commission = RoundToNDecimalPlaces(HistoryDealGetDouble(in_order_ticket, DEAL_COMMISSION),digits);
// string in_order_comment = HistoryDealGetString(in_order_ticket, DEAL_COMMENT);
// double in_order_swap = RoundToNDecimalPlaces(HistoryDealGetDouble(in_order_ticket, DEAL_SWAP),digits);
//
//
// string result[];
// string sep = "_";
// ushort u_sep;
// u_sep = StringGetCharacter(sep, 0);
// int k = StringSplit(in_order_comment, u_sep, result);
// if(ArraySize(result)>0) {
// for(int j=total-1; j>=0; j--) {
// ulong out_order_ticket = HistoryDealGetTicket(j);
// ENUM_DEAL_ENTRY out_order_entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(out_order_ticket, DEAL_ENTRY);
// if(out_order_entry == DEAL_ENTRY_OUT || out_order_entry == DEAL_ENTRY_OUT_BY) {
// ulong out_order_positionId = HistoryDealGetInteger(out_order_ticket, DEAL_POSITION_ID);
// double out_order_commission = RoundToNDecimalPlaces(HistoryDealGetDouble(out_order_ticket, DEAL_COMMISSION),digits);
// //出方向订单(平仓)
// if(out_order_positionId == in_order_positionId && result[0] == "LeonSpikeGoldEA" && result[1] == timeframe && order_type == in_order_type && symbol == in_order_symbol) {
// double order_profit = RoundToNDecimalPlaces(HistoryDealGetDouble(out_order_ticket, DEAL_PROFIT),digits);
// if((order_profit+in_order_commission+out_order_commission+in_order_swap) < 0) {
// count++;
// } else {
// is_break =true;
// break;
//
// }
// }
// }
// }
// }
//
//
// }
// if(is_break == true) {
// break;
// }
// }
// //Print(count+"count");
// return count;
//
//}
////+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| 下单 |
//+------------------------------------------------------------------+
void SendOrders(int magic, string symbol, double lots, ENUM_SYMBOL_INFO_DOUBLE type, double sl, double tp, string comment,ulong slippage) {
CTrade trade;
trade.SetExpertMagicNumber(magic);
trade.SetDeviationInPoints(slippage);
int digits = SymbolInfoInteger(symbol, SYMBOL_DIGITS);
double price = RoundToNDecimalPlaces(SymbolInfoDouble(symbol, type),digits);
if(type == SYMBOL_BID) {
int ticket = trade.Sell(lots, symbol, price, sl, tp, comment);
if(ticket < 0) {
PrintFormat("Sell order failed. Error code: %d", GetLastError());
}
} else if (type == SYMBOL_ASK) {
int ticket = trade.Buy(lots, symbol, price, sl, tp, comment);
if(ticket < 0) {
PrintFormat("Buy order failed. Error code: %d", GetLastError());
}
}
}
//+------------------------------------------------------------------+
//| 追踪止损 |
//+------------------------------------------------------------------+
void TrailingStop() {
CTrade trade;
int totalPositions = PositionsTotal();
for(int i = 0; i < totalPositions; i++) {
ulong ticket = PositionGetTicket(i);
// 如果成功选择持仓订单
if(PositionSelectByTicket(ticket)) {
// 获取持仓订单的详细信息
string symbol = PositionGetString(POSITION_SYMBOL);
string comment = PositionGetString(POSITION_COMMENT);
double magic = PositionGetInteger(POSITION_MAGIC);
double sl = PositionGetDouble(POSITION_SL);
double tp = PositionGetDouble(POSITION_TP);
double open = PositionGetDouble(POSITION_PRICE_OPEN);
double current = PositionGetDouble(POSITION_PRICE_CURRENT);
// 获取订单类型
ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
string orderType = (positionType == POSITION_TYPE_BUY) ? "Buy" : "Sell";
string result[];
string sep = "_";
ushort u_sep;
u_sep = StringGetCharacter(sep, 0);
int k = StringSplit(comment, u_sep, result);
int digits = SymbolInfoInteger(symbol, SYMBOL_DIGITS);
if(StringLen(comment) != 0 && result[0] == "LeonSpikeGoldEA") {
if(orderType == "Sell" ) {
if((open - current) > iTrailingStopPrice) {
double new_sl = open - ((open - current) * iPriceDifferentPercent / 100);
new_sl = RoundToNDecimalPlaces(new_sl, digits);
if(new_sl < sl) {
if (!trade.PositionModify(ticket, new_sl, tp)) {
//PrintFormat("追踪损设置失败 订单 %d. 错误代码: %d", ticket, GetLastError());
} else {
//PrintFormat("%d 单的追踪止损设置为 %f", ticket, new_sl);
}
}
}
} else if(orderType == "Buy") {
if((current - open) > iTrailingStopPrice) {
double new_sl = open + ((current - open) * iPriceDifferentPercent / 100);
new_sl = RoundToNDecimalPlaces(new_sl, digits);
if(new_sl > sl) {
if (!trade.PositionModify(ticket, new_sl, tp)) {
//PrintFormat("追踪损设置失败 订单 %d. Error code: %d", ticket, GetLastError());
} else {
//PrintFormat("%d 订单的追踪止损设置为 %f", ticket, new_sl);
}
}
}
}
}
}
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| 是不否在允许交易的时间 |
//+------------------------------------------------------------------+
bool IsAllowPeriod() {
MqlDateTime dt;
TimeCurrent(dt);
if(dt.day_of_week == 5 &&dt.hour > iFriday_day_stop_trading) {
return false;
} else if(dt.day_of_week == 1 && dt.hour < iMonday_day_stop_trading) {
return false;
} else {
if(dt.hour== 0 && dt.min<=30) {
return iBlock_0000_0030;
} else if(dt.hour== 0 && dt.min>30) {
return iBlock_0030_0100;
} else if(dt.hour == 1 && dt.min<=30) {
return iBlock_0100_0130;
} else if(dt.hour == 1 && dt.min>30) {
return iBlock_0130_0200;
} else if(dt.hour == 2 && dt.min<=30) {
return iBlock_0200_0230;
} else if(dt.hour == 2 && dt.min>30) {
return iBlock_0230_0300;
} else if(dt.hour == 3 && dt.min<=30) {
return iBlock_0300_0330;
} else if(dt.hour == 3 && dt.min>30) {
return iBlock_0330_0400;
} else if(dt.hour == 4 && dt.min<=30) {
return iBlock_0400_0430;
} else if(dt.hour == 4 && dt.min>30) {
return iBlock_0430_0500;
} else if(dt.hour == 5 && dt.min<=30) {
return iBlock_0500_0530;
} else if(dt.hour == 5 && dt.min>30) {
return iBlock_0530_0600;
} else if(dt.hour == 6 && dt.min<=30) {
return iBlock_0600_0630;
} else if(dt.hour == 6 && dt.min>30) {
return iBlock_0630_0700;
} else if(dt.hour == 7 && dt.min<=30) {
return iBlock_0700_0730;
} else if(dt.hour == 7 && dt.min>30) {
return iBlock_0730_0800;
} else if(dt.hour == 8 && dt.min<=30) {
return iBlock_0800_0830;
} else if(dt.hour == 8 && dt.min>30) {
return iBlock_0830_0900;
} else if(dt.hour == 9 && dt.min<=30) {
return iBlock_0900_0930;
} else if(dt.hour == 9 && dt.min>30) {
return iBlock_0930_1000;
} else if(dt.hour == 10 && dt.min<=30) {
return iBlock_1000_1030;
} else if(dt.hour == 10 && dt.min>30) {
return iBlock_1030_1100;
} else if(dt.hour == 11 && dt.min<=30) {
return iBlock_1100_1130;
} else if(dt.hour == 11 && dt.min>30) {
return iBlock_1130_1200;
} else if(dt.hour == 12 && dt.min<=30) {
return iBlock_1200_1230;
} else if(dt.hour == 12 && dt.min>30) {
return iBlock_1230_1300;
} else if(dt.hour == 13 && dt.min<=30) {
return iBlock_1300_1330;
} else if(dt.hour == 13 && dt.min>30) {
return iBlock_1330_1400;
} else if(dt.hour == 14 && dt.min<=30) {
return iBlock_1400_1430;
} else if(dt.hour == 14 && dt.min>30) {
return iBlock_1430_1500;
} else if(dt.hour == 15 && dt.min<=30) {
return iBlock_1500_1530;
} else if(dt.hour == 15 && dt.min>30) {
return iBlock_1530_1600;
} else if(dt.hour == 16 && dt.min<=30) {
return iBlock_1600_1630;
} else if(dt.hour == 16 && dt.min>30) {
return iBlock_1630_1700;
} else if(dt.hour == 17 && dt.min<=30) {
return iBlock_1700_1730;
} else if(dt.hour == 17 && dt.min>30) {
return iBlock_1730_1800;
} else if(dt.hour == 18 && dt.min<=30) {
return iBlock_1800_1830;
} else if(dt.hour == 18 && dt.min>30) {
return iBlock_1830_1900;
} else if(dt.hour == 19 && dt.min<=30) {
return iBlock_1900_1930;
} else if(dt.hour == 19 && dt.min>30) {
return iBlock_1930_2000;
} else if(dt.hour == 20 && dt.min<=30) {
return iBlock_2000_2030;
} else if(dt.hour == 20 && dt.min>30) {
return iBlock_2030_2100;
} else if(dt.hour == 21 && dt.min<=30) {
return iBlock_2100_2130;
} else if(dt.hour == 21 && dt.min>30) {
return iBlock_2130_2200;
} else if(dt.hour == 22 && dt.min<=30) {
return iBlock_2200_2230;
} else if(dt.hour == 22 && dt.min>30) {
return iBlock_2230_2300;
} else if(dt.hour == 23 && dt.min<=30) {
return iBlock_2300_2330;
} else if(dt.hour == 23 && dt.min>30) {
return iBlock_2330_2400;
}
}
return true;
}
//+------------------------------------------------------------------+</code></pre> |
1 |
50 |
1 |
3/6/26, 8:00 PM |
3/6/26, 8:00 PM |
View Edit Delete |