2020/05/16

MetaTrader4 設定情報取得スクリプト

MetaTrader4 で、口座情報、証拠金状況情報、時刻情報、マーケット情報、商品情報を取得するスクリプトを作りました。

AccountXxx() や MarketInfo() を使って情報を取得するスクリプトはけっこうあちこちで見掛ける、珍しくもなんともないものなのですが、一応いくつか特徴があります。

  • コード値を返すものは、その意味が分かるようなメッセージにしている
  • 日付・時刻はフォーマットしている
  • サーバ時刻とローカル時刻の時差を計算している
  • 単位のある数値は、単位を表記するようにしている
    • point とか % とか
    • 例えば JPY 口座で USDCHF の情報を見ているときに、各種金額が JPY なのか USD なのか CHF なのかを明示している
  • おそらく MetaTrader5 由来だと思うのですが、AccountInfoXxx() や SymbolInfoXxx() でしか拾えない情報があるので、それらも表示するようにしている

仕様

まず、MQL4\Scripts に置いてコンパイルします。
そうしたら、ナビゲーターのスクリプトから選んで、チャートにドラッグ&ドロップすれば実行されます。
実行すると、アラートウィンドウに結果が表示されます。メッセージダイアログだとコピーできなかったので、アラートにしました。

ソースコード

#property copyright   "Copyright 2020, VIRTUE LLC Japan"
#property link        "https://www.virtue.llc"
#property version     "1.00"
#property description "Get Account, Margin, Time, Market and Symbol information."

int start() {
  string msg = "=== Account information ===\n";
  msg += "Company/Server=" + AccountCompany() + " / " + AccountServer() + "\n";
  // msg += "Number=" + AccountNumber() + "\n";
  // msg += "Name=" + AccountName() + "\n";
  msg += "TradeAllowed=" + B(AccountInfoInteger(ACCOUNT_TRADE_ALLOWED)) + "\n";
  msg += "TradeExpertAllowed=" + B(AccountInfoInteger(ACCOUNT_TRADE_EXPERT)) + "\n";
  msg += "LimitOrders=" + AccountInfoInteger(ACCOUNT_LIMIT_ORDERS) + "\n";
  string ccy = AccountCurrency();
  msg += "Currency=" + ccy + "\n";
  msg += "Leverage=" + AccountLeverage() + "\n";
  string stopout;
  if (AccountStopoutMode() == 0) {
    stopout = "%";
  } else {
    stopout = ccy;
  }
  msg += "MarginCallLevel=" + AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL) + stopout + "\n";
  msg += "StopoutLevel=" + AccountStopoutLevel() + stopout + "\n";

  msg += "=== Margin status ===\n";
  msg += "Balance=" + AccountBalance() + " " + ccy + "\n";
  msg += "Credit=" + AccountCredit() + " " + ccy + "\n";
  msg += "Profit/Loss=" + AccountProfit() + " " + ccy + "\n";
  msg += "Equity=" + AccountEquity() + " " + ccy + "\n";
  msg += "Margin=" + AccountMargin() + " " + ccy + "\n";
  int freeMarginMode = AccountFreeMarginMode();
  string freeMarginModeString = "";
  switch (freeMarginMode) {
  case 0:
    freeMarginModeString = "Floating P/L is not used";
    break;
  case 1:
    freeMarginModeString = "Floating P/L is used";
    break;
  case 2:
    freeMarginModeString = "Only floating profit is used";
    break;
  default:
    freeMarginModeString = "Only floating loss is used";
  }
  msg += "FreeMargin=" + AccountFreeMargin() + " " + ccy + " (" + freeMarginModeString + ")\n";

  msg += "=== Time information ===\n";
  datetime loc = TimeLocal();
  datetime cur = TimeCurrent();
  string offset = DoubleToString(MathRound((loc - cur) / 1800.0) / 2.0, 1);
  msg += "Local/ServerTime(Offset)=" + T(loc) + " / " + T(cur) + " (" + offset + ")\n";

  msg += "=== Current market information ===\n";
  msg += "Symbol=" + Symbol() + "\n";
  string symbolBaseCcy = SymbolInfoString(Symbol(), SYMBOL_CURRENCY_BASE);
  string symbolProfitCcy = SymbolInfoString(Symbol(), SYMBOL_CURRENCY_PROFIT);
  string symbolMarginCcy = SymbolInfoString(Symbol(), SYMBOL_CURRENCY_MARGIN);
  int digits = MarketInfo(Symbol(), MODE_DIGITS);
  datetime bar = MarketInfo(Symbol(), MODE_TIME);
  bool spreadFloat = SymbolInfoInteger(Symbol(), SYMBOL_SPREAD_FLOAT);
  msg += "TickTimestamp/Bid/Ask(Spread)=" + T(bar) + " " + DoubleToString(MarketInfo(Symbol(), MODE_BID), digits) + "/" + DoubleToString(MarketInfo(Symbol(), MODE_ASK), digits) + "(" + MarketInfo(Symbol(), MODE_SPREAD) + "/" + (spreadFloat ? "variable" : "fixed") + ")\n";
  msg += "Low/High=" + DoubleToString(MarketInfo(Symbol(), MODE_LOW), digits) + "/" + DoubleToString(MarketInfo(Symbol(), MODE_HIGH), digits) + "\n";
  int swapMode = MarketInfo(Symbol(), MODE_SWAPTYPE);
  string swapModeString;
  switch (swapMode) {
  case 0:
    swapModeString = "point";
    break;
  case 1:
    swapModeString = symbolBaseCcy;
    break;
  case 2:
    swapModeString = "%";
    break;
  default:
    swapModeString = symbolMarginCcy;
  }
  msg += "SwapLong/Short=" + MarketInfo(Symbol(), MODE_SWAPLONG) + "/" + MarketInfo(Symbol(), MODE_SWAPSHORT) + " " + swapModeString + "\n";

  msg += "=== Symbol information ===\n";
  double point = MarketInfo(Symbol(), MODE_POINT);
  msg += "TradeAllowed=" + B(MarketInfo(Symbol(), MODE_TRADEALLOWED)) + "\n";
  msg += "CloseByAllowed=" + B(MarketInfo(Symbol(), MODE_CLOSEBY_ALLOWED)) + "\n";
  // msg += "TradeCalcMode=" + SymbolInfoInteger(Symbol(), SYMBOL_TRADE_CALC_MODE) + "\n";
  int tradeMode = SymbolInfoInteger(Symbol(), SYMBOL_TRADE_MODE);
  string tradeModeString;
  switch (tradeMode) {
  case SYMBOL_TRADE_MODE_DISABLED:
    tradeModeString = "disabled";
    break;
  case SYMBOL_TRADE_MODE_LONGONLY:
    tradeModeString = "long only";
    break;
  case SYMBOL_TRADE_MODE_SHORTONLY:
    tradeModeString = "short only";
    break;
  case SYMBOL_TRADE_MODE_CLOSEONLY:
    tradeModeString = "close only";
    break;
  default:
    tradeModeString = "full";
  }
  msg += "TradeMode=" + tradeMode + " (" + tradeModeString + ")\n";
  int tradeExeMode = SymbolInfoInteger(Symbol(), SYMBOL_TRADE_EXEMODE);
  string tradeExeModeString;
  switch (tradeExeMode) {
  case SYMBOL_TRADE_EXECUTION_REQUEST:
    tradeExeModeString = "request";
    break;
  case SYMBOL_TRADE_EXECUTION_INSTANT:
    tradeExeModeString = "instant";
    break;
  case SYMBOL_TRADE_EXECUTION_MARKET:
    tradeExeModeString = "market";
    break;
  default:
    tradeExeModeString = "exchange";
  }
  msg += "ExecutionMode=" + tradeExeMode + " (" + tradeExeModeString + ")\n";
  msg += "Digits/Point=" + digits + " / " + point + " " + symbolProfitCcy + "\n";
  msg += "LotSize=" + MarketInfo(Symbol(), MODE_LOTSIZE) + " " + symbolMarginCcy + "\n";
  msg += "LotStep=" + MarketInfo(Symbol(), MODE_LOTSTEP) + "\n";
  msg += "MinLot=" + MarketInfo(Symbol(), MODE_MINLOT) + "\n";
  msg += "MaxLot=" + MarketInfo(Symbol(), MODE_MAXLOT) + "\n";
  msg += "TickSize=" + MarketInfo(Symbol(), MODE_TICKSIZE) + " " + symbolProfitCcy + "\n";
  msg += "TickValue=" + MarketInfo(Symbol(), MODE_TICKVALUE) + " " + ccy + "\n";
  msg += "MarginRequired=" + MarketInfo(Symbol(), MODE_MARGINREQUIRED) + " " + ccy + "\n";
  msg += "MarginInit=" + MarketInfo(Symbol(), MODE_MARGININIT) + " " + ccy + "\n";
  msg += "MarginMaintenance=" + MarketInfo(Symbol(), MODE_MARGINMAINTENANCE) + " " + ccy + "\n";
  msg += "MarginHedged=" + MarketInfo(Symbol(), MODE_MARGINHEDGED) + " " + ccy + "\n";
  double stopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL);
  msg += "StopLevel=" + stopLevel + " point (" + DoubleToString(stopLevel * point, digits) + ")\n";
  double freezeLevel = MarketInfo(Symbol(), MODE_FREEZELEVEL);
  msg += "FreezeLevel=" + freezeLevel + " point (" + DoubleToString(freezeLevel * point, digits) + ")\n";
  msg += "Starting/Expiration=" + MarketInfo(Symbol(), MODE_STARTING) + "/" + MarketInfo(Symbol(), MODE_EXPIRATION) + "\n";
  int profitCalcMode = MarketInfo(Symbol(), MODE_PROFITCALCMODE);
  string profitCalcModeString;
  switch (profitCalcMode) {
  case 0:
    profitCalcModeString = "Forex";
    break;
  case 1:
    profitCalcModeString = "CFD";
    break;
  default:
    profitCalcModeString = "Futures";
  }
  msg += "ProfitCalcMode=" + profitCalcMode + " (" + profitCalcModeString + ")\n";
  int marginCalcMode = MarketInfo(Symbol(), MODE_MARGINCALCMODE);
  string marginCalcModeString;
  switch (marginCalcMode) {
  case 0:
    marginCalcModeString = "Forex";
    break;
  case 1:
    marginCalcModeString = "CFD";
    break;
  case 2:
    marginCalcModeString = "Futures";
    break;
  default:
    marginCalcModeString = "CFD for indices";
  }
  msg += "MarginCalcMode=" + marginCalcMode + " (" + marginCalcModeString + ")\n";

  Alert(msg);
  return(0);
}

string B(const bool b) {
  return b ? "true" : "false";
}

string T(const datetime t) {
  return TimeToString(t, TIME_DATE | TIME_SECONDS);
}

実行結果例

=== Account information ===
Company/Server=*** / ***
TradeAllowed=true
TradeExpertAllowed=true
LimitOrders=200
Currency=JPY
Leverage=888
MarginCallLevel=50%
StopoutLevel=20%
=== Margin status ===
Balance=4998160 JPY
Credit=0 JPY
Profit/Loss=-14082 JPY
Equity=4984078 JPY
Margin=6551.61309959 JPY
FreeMargin=4977526.38690041 JPY (Floating P/L is used)
=== Time information ===
Local/ServerTime(Offset)=2020.05.16 04:44:38 / 2020.05.15 22:44:37 (6.0)
=== Current market information ===
Symbol=USDCHF
TickTimestamp/Bid/Ask(Spread)=2020.05.15 22:44:32 0.97241/0.97259(18/variable)
Low/High=0.96972/0.97436
SwapLong/Short=-0.35/-5.01 point
=== Symbol information ===
TradeAllowed=true
CloseByAllowed=true
TradeMode=2 (full)
ExecutionMode=2 (market)
Digits/Point=5 / 0.00001 CHF
LotSize=100000 USD
LotStep=0.01
MinLot=0.01
MaxLot=10000
TickSize=0.00001 CHF
TickValue=110.261 JPY
MarginRequired=12077.59 JPY
MarginInit=0 JPY
MarginMaintenance=0 JPY
MarginHedged=0 JPY
StopLevel=50 point (0.00050)
FreezeLevel=0 point (0.00000)
Starting/Expiration=0/0
ProfitCalcMode=0 (Forex)
MarginCalcMode=0 (Forex)