193 行
7.2 KiB
MQL5
193 行
7.2 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| MarginProfitMeter.mqh |
| |||
//| Copyright (c) 2018-2022, Marketeer |
| |||
//| https://www.mql5.com/en/users/marketeer |
| |||
//| A set of functions to calculate margin, potential profit/loss, |
| |||
//| point value and coversion rates. |
| |||
//+------------------------------------------------------------------+
| |||
| |||
namespace MPM
| |||
{
| |||
// Analogue of built-in OrderCalcMargin which is not allowed in indicators
| |||
bool OrderCalcMargin(const ENUM_ORDER_TYPE action, const string symbol,
| |||
double volume, double price, double &margin)
| |||
{
| |||
double marginInit, marginMain;
| |||
MqlTick tick;
| |||
| |||
// check given parameters
| |||
if((action != ORDER_TYPE_BUY && action != ORDER_TYPE_SELL)
| |||
|| volume < 0 || price < 0) return false;
| |||
| |||
// request all properties used in the formulae
| |||
if(!SymbolInfoTick(symbol, tick)) return false;
| |||
if(!SymbolInfoMarginRate(symbol, action, marginInit, marginMain)) return false;
| |||
const double contract = SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE);
| |||
long leverage = AccountInfoInteger(ACCOUNT_LEVERAGE);
| |||
if(volume == 0) volume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
| |||
if(price == 0) price = action == ORDER_TYPE_BUY ? tick.ask : tick.bid;
| |||
| |||
if(margin == DBL_MAX) marginInit = marginMain;
| |||
margin = 0;
| |||
| |||
const ENUM_SYMBOL_CALC_MODE m =
| |||
(ENUM_SYMBOL_CALC_MODE)SymbolInfoInteger(symbol, SYMBOL_TRADE_CALC_MODE);
| |||
| |||
switch(m)
| |||
{
| |||
case SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE:
| |||
leverage = 1;
| |||
| |||
case SYMBOL_CALC_MODE_FOREX:
| |||
margin = volume * contract / leverage * marginInit;
| |||
break;
| |||
| |||
case SYMBOL_CALC_MODE_CFD:
| |||
margin = volume * contract * price * marginInit;
| |||
break;
| |||
| |||
case SYMBOL_CALC_MODE_CFDINDEX:
| |||
margin = volume * contract * price * SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE)
| |||
/ SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE) * marginInit;
| |||
break;
| |||
| |||
case SYMBOL_CALC_MODE_CFDLEVERAGE:
| |||
margin = volume * contract * price / leverage * marginInit;
| |||
break;
| |||
| |||
case SYMBOL_CALC_MODE_EXCH_STOCKS:
| |||
case SYMBOL_CALC_MODE_EXCH_STOCKS_MOEX:
| |||
if(price == 0) price = tick.last;
| |||
margin = volume * contract * price * marginInit;
| |||
break;
| |||
| |||
case SYMBOL_CALC_MODE_FUTURES:
| |||
case SYMBOL_CALC_MODE_EXCH_FUTURES:
| |||
case SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS:
| |||
margin = volume * SymbolInfoDouble(symbol, SYMBOL_MARGIN_INITIAL) * marginInit;
| |||
break;
| |||
default:
| |||
PrintFormat("Unsupported symbol %s trade mode: %s", symbol, EnumToString(m));
| |||
}
| |||
| |||
string account = AccountInfoString(ACCOUNT_CURRENCY);
| |||
string current = SymbolInfoString(symbol, SYMBOL_CURRENCY_MARGIN);
| |||
if(current != account)
| |||
{
| |||
if(!Convert(current, account, action == ORDER_TYPE_SELL, margin)) return false;
| |||
}
| |||
| |||
return true;
| |||
}
| |||
| |||
// Search available symbols for a one built of the 'current' and 'account' currencies
| |||
int FindExchangeRate(const string current, const string account, string &result)
| |||
{
| |||
for(int i = 0; i < SymbolsTotal(true); i++)
| |||
{
| |||
const string symbol = SymbolName(i, true);
| |||
const ENUM_SYMBOL_CALC_MODE m =
| |||
(ENUM_SYMBOL_CALC_MODE)SymbolInfoInteger(symbol, SYMBOL_TRADE_CALC_MODE);
| |||
if(m == SYMBOL_CALC_MODE_FOREX || m == SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE)
| |||
{
| |||
string base = SymbolInfoString(symbol, SYMBOL_CURRENCY_BASE);
| |||
string profit = SymbolInfoString(symbol, SYMBOL_CURRENCY_PROFIT);
| |||
if(base == current && profit == account)
| |||
{
| |||
result = symbol;
| |||
return +1;
| |||
}
| |||
else
| |||
if(base == account && profit == current)
| |||
{
| |||
result = symbol;
| |||
return -1;
| |||
}
| |||
}
| |||
}
| |||
return 0;
| |||
}
| |||
| |||
// Estimate a rate of specified symbol at a given moment in past
| |||
double GetHistoricPrice(const string symbol, const datetime moment, const bool ask)
| |||
{
| |||
const int offset = iBarShift(symbol, _Period, moment);
| |||
// NB: iClose can hold Last price instead of Bid for exchange symbols
| |||
// there is no fast way to handle this, only tick history analysis
| |||
return iClose(symbol, _Period, offset) +
| |||
(ask ? iSpread(symbol, _Period, offset) * SymbolInfoDouble(symbol, SYMBOL_POINT) : 0);
| |||
}
| |||
| |||
// Convert amount of 'current' money into 'account' money
| |||
bool Convert(const string current, const string account,
| |||
const bool ask, double &margin, const datetime moment = 0)
| |||
{
| |||
string rate;
| |||
int dir = FindExchangeRate(current, account, rate);
| |||
if(dir == +1)
| |||
{
| |||
margin *= moment == 0 ?
| |||
SymbolInfoDouble(rate, ask ? SYMBOL_BID : SYMBOL_ASK) :
| |||
GetHistoricPrice(rate, moment, ask);
| |||
}
| |||
else if(dir == -1)
| |||
{
| |||
margin /= moment == 0 ?
| |||
SymbolInfoDouble(rate, ask ? SYMBOL_ASK : SYMBOL_BID) :
| |||
GetHistoricPrice(rate, moment, ask);
| |||
}
| |||
else
| |||
{
| |||
static bool once = false;
| |||
if(!once)
| |||
{
| |||
Print("Can't convert ", current, " -> ", account);
| |||
once = true;
| |||
}
| |||
}
| |||
return true;
| |||
}
| |||
| |||
// Return point value (in account currency) of specific symbol
| |||
double PointValue(const string symbol, const bool ask = false, const datetime moment = 0)
| |||
{
| |||
const double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
| |||
const double contract = SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE);
| |||
const ENUM_SYMBOL_CALC_MODE m =
| |||
(ENUM_SYMBOL_CALC_MODE)SymbolInfoInteger(symbol, SYMBOL_TRADE_CALC_MODE);
| |||
double result = 0;
| |||
| |||
switch(m)
| |||
{
| |||
case SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE:
| |||
case SYMBOL_CALC_MODE_FOREX:
| |||
case SYMBOL_CALC_MODE_CFD:
| |||
case SYMBOL_CALC_MODE_CFDINDEX:
| |||
case SYMBOL_CALC_MODE_CFDLEVERAGE:
| |||
case SYMBOL_CALC_MODE_EXCH_STOCKS:
| |||
case SYMBOL_CALC_MODE_EXCH_STOCKS_MOEX:
| |||
result = point * contract;
| |||
break;
| |||
| |||
case SYMBOL_CALC_MODE_FUTURES:
| |||
case SYMBOL_CALC_MODE_EXCH_FUTURES:
| |||
case SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS:
| |||
result = point * SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE)
| |||
/ SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
| |||
break;
| |||
default:
| |||
PrintFormat("Unsupported symbol %s trade mode: %s", symbol, EnumToString(m));
| |||
}
| |||
| |||
string account = AccountInfoString(ACCOUNT_CURRENCY);
| |||
string current = SymbolInfoString(symbol, SYMBOL_CURRENCY_PROFIT);
| |||
| |||
if(current != account)
| |||
{
| |||
if(!Convert(current, account, ask, result, moment)) return 0;
| |||
}
| |||
| |||
return result;
| |||
}
| |||
};
| |||
//+------------------------------------------------------------------+
|