存成 MQL5/Scripts/Lesson8Functions.mq5。它示範成交量正規化與 point 轉價格——第三部分與第四部分每一個 EA 都會重複使用的兩個 helper。
//+------------------------------------------------------------------+
//| Lesson 8 - Reusable helpers and the standard library |
//+------------------------------------------------------------------+
#property copyright "Strategist Academy"
#property version "1.00"
#include <Trade/Trade.mqh>
//+------------------------------------------------------------------+
//| Round a volume to what the broker actually accepts |
//+------------------------------------------------------------------+
double NormalizeVolumeFor(const string sym, double vol)
{
double vMin = SymbolInfoDouble(sym, SYMBOL_VOLUME_MIN);
double vMax = SymbolInfoDouble(sym, SYMBOL_VOLUME_MAX);
double vStep = SymbolInfoDouble(sym, SYMBOL_VOLUME_STEP);
vol = MathMax(vMin, MathMin(vMax, vol));
if(vStep > 0)
vol = vMin + MathFloor((vol - vMin) / vStep + 0.0000001) * vStep;
return NormalizeDouble(vol, 2);
}
//+------------------------------------------------------------------+
//| Convert a distance in points into an absolute price |
//+------------------------------------------------------------------+
double PointsToPrice(const double points, const double fromPrice, const bool below)
{
double offset = points * _Point;
return below ? NormalizeDouble(fromPrice - offset, _Digits)
: NormalizeDouble(fromPrice + offset, _Digits);
}
//+------------------------------------------------------------------+
//| Is there already a position opened by this magic number? |
//+------------------------------------------------------------------+
bool HasPosition(const string sym, const ulong magic)
{
if(!PositionSelect(sym))
return false;
return ((ulong)PositionGetInteger(POSITION_MAGIC) == magic);
}
void OnStart()
{
string sym = _Symbol;
Print("Volume normalisation on ", sym);
Print(" 0.137 -> ", DoubleToString(NormalizeVolumeFor(sym, 0.137), 2));
Print(" 1.005 -> ", DoubleToString(NormalizeVolumeFor(sym, 1.005), 2));
Print(" 999.0 -> ", DoubleToString(NormalizeVolumeFor(sym, 999.0), 2), " (clamped to max)");
double bid = SymbolInfoDouble(sym, SYMBOL_BID);
double ask = SymbolInfoDouble(sym, SYMBOL_ASK);
Print("Stop 200 points below bid: ", DoubleToString(PointsToPrice(200, bid, true), _Digits));
Print("Target 400 points above ask: ", DoubleToString(PointsToPrice(400, ask, false), _Digits));
Print("Has position with magic 12345? ", HasPosition(sym, 12345) ? "yes" : "no");
// CTrade is ready to use - Part 3 will actually send orders with it.
CTrade trade;
trade.SetExpertMagicNumber(12345);
trade.SetDeviationInPoints(10);
trade.SetTypeFillingBySymbol(sym);
Print("CTrade configured. Filling mode selected by symbol: ",
EnumToString((ENUM_ORDER_TYPE_FILLING)SymbolInfoInteger(sym, SYMBOL_FILLING_MODE)));
}