116 lines
4.7 KiB
MQL5
116 lines
4.7 KiB
MQL5
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| IVProviderNative.mqh |
|
||
|
|
//| MMQ — Muhammad Minhas Qamar |
|
||
|
|
//| www.mql5.com/en/articles/23385 |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#property copyright "MMQ — Muhammad Minhas Qamar"
|
||
|
|
#property link "https://www.mql5.com/en/articles/23385"
|
||
|
|
#property version "1.00"
|
||
|
|
|
||
|
|
#ifndef IVSURFACE_IVPROVIDERNATIVE_MQH
|
||
|
|
#define IVSURFACE_IVPROVIDERNATIVE_MQH
|
||
|
|
|
||
|
|
#include <IVSurface/BlackScholes.mqh>
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Reads the broker's native MetaTrader 5 option symbols and |
|
||
|
|
//| produces the same OptionQuote list the CSV provider does. |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
class CIVProviderNative
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
//--- underlying: base symbol (e.g. "SP" / "GAZP"); rate: risk-free
|
||
|
|
bool Load(const string underlying, const double rate, OptionQuote &out[]);
|
||
|
|
|
||
|
|
private:
|
||
|
|
bool IsOption(const string sym) const;
|
||
|
|
};
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| A symbol is an option if the server reports an option right for |
|
||
|
|
//| it. Brokers that do not support options return an error / zero |
|
||
|
|
//| here, so this doubles as the "options available?" test. |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CIVProviderNative::IsOption(const string sym) const
|
||
|
|
{
|
||
|
|
long right = 0;
|
||
|
|
if(!SymbolInfoInteger(sym, SYMBOL_OPTION_RIGHT, right))
|
||
|
|
return(false);
|
||
|
|
//--- options carry a valid strike; use it as a second confirmation
|
||
|
|
double strike = SymbolInfoDouble(sym, SYMBOL_OPTION_STRIKE);
|
||
|
|
return(strike > 0.0);
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Enumerate all symbols, collect the options on the requested |
|
||
|
|
//| underlying, and build one OptionQuote per contract. |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool CIVProviderNative::Load(const string underlying, const double rate, OptionQuote &out[])
|
||
|
|
{
|
||
|
|
ArrayResize(out, 0);
|
||
|
|
int total = SymbolsTotal(false); // false = all symbols, not just Market Watch
|
||
|
|
if(total <= 0)
|
||
|
|
{
|
||
|
|
Print("CIVProviderNative: no symbols available");
|
||
|
|
return(false);
|
||
|
|
}
|
||
|
|
|
||
|
|
double spot = SymbolInfoDouble(underlying, SYMBOL_BID);
|
||
|
|
if(spot <= 0.0)
|
||
|
|
spot = SymbolInfoDouble(underlying, SYMBOL_LAST);
|
||
|
|
|
||
|
|
datetime now = TimeCurrent();
|
||
|
|
if(now == 0)
|
||
|
|
now = TimeLocal();
|
||
|
|
int found = 0, withServerIV = 0;
|
||
|
|
|
||
|
|
for(int i = 0; i < total; i++)
|
||
|
|
{
|
||
|
|
string sym = SymbolName(i, false);
|
||
|
|
if(!IsOption(sym))
|
||
|
|
continue;
|
||
|
|
|
||
|
|
//--- match the underlying via SYMBOL_BASIS (the derivative's base asset)
|
||
|
|
string basis = SymbolInfoString(sym, SYMBOL_BASIS);
|
||
|
|
if(basis != underlying)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
//--- make sure the symbol's quotes are available
|
||
|
|
SymbolSelect(sym, true);
|
||
|
|
|
||
|
|
OptionQuote q;
|
||
|
|
long right = (long)SymbolInfoInteger(sym, SYMBOL_OPTION_RIGHT);
|
||
|
|
q.right = (right == SYMBOL_OPTION_RIGHT_PUT) ? OPT_PUT : OPT_CALL;
|
||
|
|
q.strike = SymbolInfoDouble(sym, SYMBOL_OPTION_STRIKE);
|
||
|
|
q.expiry = (datetime)SymbolInfoInteger(sym, SYMBOL_EXPIRATION_TIME);
|
||
|
|
q.spot = spot;
|
||
|
|
q.rate = rate;
|
||
|
|
|
||
|
|
//--- option mid price from the current bid/ask
|
||
|
|
double bid = SymbolInfoDouble(sym, SYMBOL_BID);
|
||
|
|
double ask = SymbolInfoDouble(sym, SYMBOL_ASK);
|
||
|
|
q.price = (bid > 0.0 && ask > 0.0) ? 0.5 * (bid + ask) : SymbolInfoDouble(sym, SYMBOL_LAST);
|
||
|
|
|
||
|
|
//--- prefer the server-computed implied volatility if present
|
||
|
|
double serverVol = SymbolInfoDouble(sym, SYMBOL_PRICE_VOLATILITY);
|
||
|
|
double T = (double)(q.expiry - now) / (365.0 * 24 * 3600);
|
||
|
|
if(serverVol > 0.0)
|
||
|
|
{ q.iv = serverVol / 100.0; withServerIV++; } // property is a percentage
|
||
|
|
else
|
||
|
|
q.iv = ImpliedVol(q.right, q.price, q.spot, q.strike, q.rate, 0.0, T);
|
||
|
|
|
||
|
|
int s = ArraySize(out);
|
||
|
|
ArrayResize(out, s + 1);
|
||
|
|
out[s] = q;
|
||
|
|
found++;
|
||
|
|
}
|
||
|
|
|
||
|
|
PrintFormat("CIVProviderNative: underlying=%s spot=%.4f options found=%d server IV on %d",
|
||
|
|
underlying, spot, found, withServerIV);
|
||
|
|
if(found == 0)
|
||
|
|
Print("CIVProviderNative: no option symbols matched. This account/broker may not offer options, or the underlying name differs from SYMBOL_BASIS.");
|
||
|
|
return(found > 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif // IVSURFACE_IVPROVIDERNATIVE_MQH
|
||
|
|
//+------------------------------------------------------------------+
|