5312 lines
95 KiB
Plaintext
5312 lines
95 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Common Library
|
|
// --------------------------------------
|
|
// Name: XCommon
|
|
// Description: provide all commonly used functions ...
|
|
//
|
|
//
|
|
// Maintainer:
|
|
// ------------
|
|
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
|
|
//
|
|
//////////////////////////////////////////////////////
|
|
//
|
|
// Global Properties ...
|
|
#property library
|
|
#property copyright "Copyright 2023, SaherElm IT Center"
|
|
#property link "https://www.saherelm.ir"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
//
|
|
// START Inputs ...
|
|
//
|
|
|
|
//
|
|
// END Inputs ...
|
|
//
|
|
|
|
//
|
|
// Include Models Library ...
|
|
#include "x-saherelm.models.lib.mq5"
|
|
#include "../Classes/x-saherelm.xmd5.class.mq5"
|
|
|
|
//
|
|
// START Global Definitions: Variables, Properties and etc ...
|
|
//
|
|
//
|
|
// END Global Definitions: Variables, Properties and etc ...
|
|
//
|
|
|
|
//
|
|
// START Provided Functions ...
|
|
//
|
|
|
|
//
|
|
// Detect is new Candle or not ...
|
|
bool IsNewCandle()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
static int barsOnChart = 0;
|
|
int currentBarsOnChart = Bars(_Symbol, _Period);
|
|
result = currentBarsOnChart > barsOnChart;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
barsOnChart = currentBarsOnChart;
|
|
result = true;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool IsNewCandle(
|
|
string mSymbol, // Trading Symbol ...
|
|
ENUM_TIMEFRAMES mPeriod // Trading Time Frame ...
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
static string mChartTags[];
|
|
static int mChartBars[];
|
|
|
|
//
|
|
string chTag = mSymbol + "," + ToString(mPeriod);
|
|
|
|
//
|
|
int currChTagIdx = -1;
|
|
int chCountedBars = 0;
|
|
int currentBars = Bars(mSymbol, mPeriod);
|
|
|
|
//
|
|
if (ArraySize(mChartTags) > 0)
|
|
{
|
|
//
|
|
for (int i = 0; i < ArraySize(mChartTags); i++)
|
|
{
|
|
//
|
|
string iTag = mChartTags[i];
|
|
if (iTag != chTag)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
currChTagIdx = i;
|
|
break;
|
|
}
|
|
|
|
//
|
|
if (currChTagIdx > -1)
|
|
{
|
|
chCountedBars = mChartBars[currChTagIdx];
|
|
}
|
|
}
|
|
|
|
//
|
|
result = currentBars > chCountedBars;
|
|
if (result)
|
|
{
|
|
//
|
|
if (currChTagIdx > -1)
|
|
{
|
|
//
|
|
mChartTags[currChTagIdx] = chTag;
|
|
mChartBars[currChTagIdx] = currentBars;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
Add(chTag, mChartTags);
|
|
Add(currentBars, mChartBars);
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double XNZ(double check, double val = 0)
|
|
{
|
|
if (check == EMPTY_VALUE || check == 0)
|
|
{
|
|
return val;
|
|
}
|
|
else
|
|
{
|
|
return check;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Retrive Ask Price ...
|
|
double GetAsk()
|
|
{
|
|
return SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
}
|
|
double GetAsk(
|
|
string symbol // selected symbol for calculations
|
|
)
|
|
{
|
|
//
|
|
double result = SymbolInfoDouble(symbol, SYMBOL_ASK);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Bid Price ...
|
|
double GetBid()
|
|
{
|
|
return SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
}
|
|
double GetBid(
|
|
string symbol // selected symbol for calculations
|
|
)
|
|
{
|
|
//
|
|
double result = SymbolInfoDouble(symbol, SYMBOL_BID);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate and Retrieve Spread Price ...
|
|
double GetSpread()
|
|
{
|
|
//
|
|
double ask = GetAsk();
|
|
double bid = GetBid();
|
|
double result = MathAbs(ask - bid);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
double GetSpread(
|
|
string symbol // selected symbol for calculations
|
|
)
|
|
{
|
|
//
|
|
double ask = GetAsk(symbol);
|
|
double bid = GetBid(symbol);
|
|
double result = MathAbs(ask - bid);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Points ...
|
|
double GetPoints()
|
|
{
|
|
return _Point;
|
|
}
|
|
double GetPoints(
|
|
string symbol // selected symbol for calculations
|
|
)
|
|
{
|
|
//
|
|
double result = SymbolInfoDouble(symbol, SYMBOL_POINT);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Digits ...
|
|
int GetDigits()
|
|
{
|
|
return _Digits;
|
|
}
|
|
int GetDigits(
|
|
string symbol // selected symbol for calculations
|
|
)
|
|
{
|
|
//
|
|
int result = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Signal Entry ...
|
|
double GetEntry(
|
|
ENUM_POSITION_TYPE type // Get entry price for Which direction trade ...
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
bool isLong = type == POSITION_TYPE_BUY;
|
|
result = isLong ? GetAsk() : GetBid();
|
|
result = NormalizePrice(result);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
double GetEntry(
|
|
string symbol, // Specified Symbol
|
|
ENUM_POSITION_TYPE type // Get entry price for Which direction trade ...
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
bool isLong = type == POSITION_TYPE_BUY;
|
|
result = isLong ? GetAsk(symbol) : GetBid(symbol);
|
|
result = NormalizePrice(result, symbol);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Signal Exit ...
|
|
double GetExit(
|
|
ENUM_POSITION_TYPE type // Get entry price for Which direction trade ...
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
bool isLong = type == POSITION_TYPE_BUY;
|
|
result = isLong ? GetBid() : GetAsk();
|
|
result = NormalizePrice(result);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
double GetExit(
|
|
string symbol, // Specified Symbol
|
|
ENUM_POSITION_TYPE type // Get entry price for Which direction trade ...
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
bool isLong = type == POSITION_TYPE_BUY;
|
|
result = isLong ? GetBid(symbol) : GetAsk(symbol);
|
|
result = NormalizePrice(result, symbol);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Determine a Position type is Long or not ...
|
|
bool IsLong(ENUM_POSITION_TYPE type)
|
|
{
|
|
//
|
|
bool result = type == POSITION_TYPE_BUY;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool IsLong(ENUM_ORDER_TYPE type)
|
|
{
|
|
//
|
|
bool result = type == ORDER_TYPE_BUY;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Determine a Position type is Short or not ...
|
|
bool IsShort(ENUM_POSITION_TYPE type)
|
|
{
|
|
//
|
|
bool result = type == POSITION_TYPE_SELL;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool IsShort(ENUM_ORDER_TYPE type)
|
|
{
|
|
//
|
|
bool result = type == ORDER_TYPE_SELL;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get 1 Pip in Price Value ...
|
|
double GetPipPrice()
|
|
{
|
|
//
|
|
double result = _Point;
|
|
if (_Digits == 3 || _Digits == 5)
|
|
{
|
|
result *= 10;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
double GetPipPrice(
|
|
string symbol // selected symbol for calculations
|
|
)
|
|
{
|
|
//
|
|
double symbolPoint = GetPoints(symbol);
|
|
int symbolDigits = GetDigits(symbol);
|
|
|
|
//
|
|
double result = symbolPoint;
|
|
if (symbolDigits == 3 || symbolDigits == 5)
|
|
{
|
|
result *= 10;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts Pips To Price ...
|
|
double PipsToPrice(
|
|
int pips // pips amount
|
|
)
|
|
{
|
|
//
|
|
int digits = GetDigits();
|
|
double pipValue = GetPipPrice();
|
|
double result = pips * pipValue;
|
|
|
|
//
|
|
result = NormalizeDouble(result, digits);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
double PipsToPrice(
|
|
double pips // pips amount
|
|
)
|
|
{
|
|
//
|
|
int digits = GetDigits();
|
|
double pipValue = GetPipPrice();
|
|
double result = pips * pipValue;
|
|
|
|
//
|
|
result = NormalizeDouble(result, digits);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
double PipsToPrice(
|
|
string symbol, // selected symbol for calculation
|
|
int pips // pips amount
|
|
)
|
|
{
|
|
//
|
|
int digits = GetDigits(symbol);
|
|
double pipValue = GetPipPrice(symbol);
|
|
double result = pips * pipValue;
|
|
|
|
//
|
|
result = NormalizeDouble(result, digits);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
double PipsToPrice(
|
|
string symbol, // selected symbol for calculation
|
|
double pips // pips amount
|
|
)
|
|
{
|
|
//
|
|
int digits = GetDigits(symbol);
|
|
double pipValue = GetPipPrice(symbol);
|
|
double result = pips * pipValue;
|
|
|
|
//
|
|
result = NormalizeDouble(result, digits);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts Price to Pips ...
|
|
double PriceToPips(
|
|
double price // the price amount which required to calculate
|
|
)
|
|
{
|
|
//
|
|
int digits = GetDigits();
|
|
double pipPrice = GetPipPrice();
|
|
|
|
//
|
|
double result = price / pipPrice;
|
|
|
|
//
|
|
result = NormalizeDouble(result, digits);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
double PriceToPips(
|
|
string symbol, // Selected Symbol
|
|
double price // the price amount which required to calculate
|
|
)
|
|
{
|
|
//
|
|
int digits = GetDigits(symbol);
|
|
double pipPrice = GetPipPrice(symbol);
|
|
|
|
//
|
|
double result = price / pipPrice;
|
|
|
|
//
|
|
result = NormalizeDouble(result, digits);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Convert Price to Point ...
|
|
double PriceToPoint(
|
|
double price // the price amount which required to calculate
|
|
)
|
|
{
|
|
return PriceToPoint(_Symbol, price);
|
|
}
|
|
double PriceToPoint(
|
|
string symbol, // Selected Symbol
|
|
double price // the price amount which required to calculate
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
double point = GetPoints(symbol);
|
|
result = price / point;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts Point to Price ...
|
|
double PointToPrice(
|
|
double points // Points Size
|
|
)
|
|
{
|
|
return PointToPrice(_Symbol, points);
|
|
}
|
|
double PointToPrice(
|
|
string symbol, // Selected Symbol
|
|
double points // Points Size
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
double point = GetPoints(symbol);
|
|
result = points * point;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// CANDLES ...
|
|
|
|
//
|
|
// Validate Candle ...
|
|
bool IsValid(
|
|
XOHCL &candle // specified candle
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
candle.open > 0 &&
|
|
candle.close > 0 &&
|
|
candle.high > 0 &&
|
|
candle.low > 0
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get a Candle Body ...
|
|
double GetCandleBody(
|
|
XOHCL &candle // specified candle
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
bool isValid = IsValid(candle);
|
|
if (!isValid)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = MathAbs(candle.open - candle.close);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get a Candle Range ...
|
|
double GetCandleRange(
|
|
XOHCL &candle // specified candle
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
bool isValid = IsValid(candle);
|
|
if (!isValid)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = MathAbs(candle.high - candle.low);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get a Candle Shadow ...
|
|
double GetCandleShadow(
|
|
XOHCL &candle // specified candle
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
bool isValid = IsValid(candle);
|
|
if (!isValid)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
double range = GetCandleRange(candle);
|
|
double body = GetCandleBody(candle);
|
|
|
|
//
|
|
result = MathAbs(range - body);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve High Shadow of Candle ...
|
|
double GetCandleHighShadow(
|
|
XOHCL &candle // specified candle
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
bool isValid = IsValid(candle);
|
|
if (!isValid)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double upPrice = MathMax(candle.open, candle.close);
|
|
|
|
//
|
|
result = candle.high - upPrice;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Low Shadow of Candle ...
|
|
double GetCandleLowShadow(
|
|
XOHCL &candle // specified candle
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
bool isValid = IsValid(candle);
|
|
if (!isValid)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double downPrice = MathMin(candle.open, candle.close);
|
|
|
|
//
|
|
result = downPrice - candle.low;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check a Candle is Base Candle for RTM or not ...
|
|
bool IsBaseCandle(
|
|
XOHCL &candle // specified candle
|
|
)
|
|
{
|
|
//
|
|
double range = GetCandleRange(candle);
|
|
double body = GetCandleBody(candle);
|
|
|
|
//
|
|
bool result = body > range;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Candle Body Bigger Than it's Shadow ...
|
|
bool CandleHasStrongBody(XOHCL &candle)
|
|
{
|
|
//
|
|
double bodySize = MathAbs(candle.open - candle.close);
|
|
double shadowSize = MathAbs(candle.high - candle.low) - bodySize;
|
|
|
|
//
|
|
bool result = bodySize > (shadowSize * 1.5);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Detect Doji Candle ...
|
|
bool IsDojiCandle(
|
|
XOHCL &candle, // Specified Candle
|
|
double detectFactor = 0.05 // Detect Factor
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bool isValid = IsValid(candle);
|
|
if (
|
|
!isValid ||
|
|
detectFactor <= 0 ||
|
|
detectFactor > 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Candle Parts ...
|
|
double body = GetCandleBody(candle);
|
|
double range = GetCandleRange(candle);
|
|
double shadows = GetCandleShadow(candle);
|
|
|
|
//
|
|
// Calculate Candle Rate ...
|
|
double factor = range * detectFactor;
|
|
double shadowFactor = (1 - detectFactor) * range;
|
|
|
|
//
|
|
result =
|
|
//
|
|
body > 0 &&
|
|
range > 0 &&
|
|
factor > 0 &&
|
|
shadows > 0 &&
|
|
body <= factor &&
|
|
shadowFactor > 0 &&
|
|
shadows >= shadowFactor
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Detect Shadows of Specific Candles must be same ..
|
|
bool IsCrossShadowCandle(
|
|
XOHCL &candle, // Specified Candle
|
|
double smoothingFactor = 0.05 // Smoothing Factor
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bool isValid = IsValid(candle);
|
|
if (!isValid ||
|
|
smoothingFactor <= 0 ||
|
|
smoothingFactor >= 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Candle Parts ...
|
|
double body = GetCandleBody(candle);
|
|
double range = GetCandleRange(candle);
|
|
double shadows = GetCandleShadow(candle);
|
|
|
|
//
|
|
double upBody = MathMax(candle.open, candle.close);
|
|
double downBody = MathMin(candle.open, candle.close);
|
|
|
|
//
|
|
double upShadow = candle.high - upBody;
|
|
double downShadow = downBody - candle.low;
|
|
|
|
//
|
|
// Calculate Candle Rate ...
|
|
double factor = range * smoothingFactor;
|
|
|
|
//
|
|
result =
|
|
upShadow > 0 &&
|
|
downShadow > 0 &&
|
|
body > 0 &&
|
|
range > 0 &&
|
|
shadows > 0 &&
|
|
((upShadow == downShadow) ||
|
|
MathAbs(upShadow - downShadow) <= factor);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Detect a Candle Shadow Hunt Specific price or not ...
|
|
bool IsShadowHuntCandle(
|
|
XOHCL &candle, // Specified Candle
|
|
double price // Specified Price
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate Args ...
|
|
bool isValid = IsValid(candle);
|
|
if (!isValid || price <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double upBody = MathMax(candle.open, candle.close);
|
|
double downBody = MathMin(candle.open, candle.close);
|
|
|
|
//
|
|
double hShadow = GetCandleHighShadow(candle);
|
|
double lShadow = GetCandleLowShadow(candle);
|
|
|
|
//
|
|
double range = GetCandleRange(candle);
|
|
double factor = range * 0.3;
|
|
|
|
//
|
|
bool isStrongHShadow = hShadow >= factor;
|
|
bool isStrongLShadow = lShadow >= factor;
|
|
|
|
//
|
|
bool isPriceUp =
|
|
price >= candle.high ||
|
|
price >= upBody;
|
|
|
|
//
|
|
result =
|
|
//
|
|
isPriceUp
|
|
//
|
|
?
|
|
//
|
|
isStrongHShadow &&
|
|
(price == candle.high ||
|
|
(price > upBody && price < candle.high))
|
|
//
|
|
:
|
|
//
|
|
isStrongLShadow &&
|
|
(price == candle.low ||
|
|
(price < downBody && price > candle.low))
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check a Candle is Bullish or not ...
|
|
bool IsBullishCandle(
|
|
XOHCL &candle // specified candle
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bool isValid = IsValid(candle);
|
|
if (!isValid)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = candle.open < candle.close;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool IsBullishCandle(
|
|
int bar_index // candle index
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
XOHCL candle = GetCandle(bar_index);
|
|
|
|
//
|
|
result = IsBullishCandle(candle);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool IsBullishCandle(
|
|
string symbol, // specify symbol
|
|
ENUM_TIMEFRAMES mPeriod, // specify timeframe
|
|
int bar_index // candle index
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
XOHCL candle = GetCandle(
|
|
symbol,
|
|
mPeriod,
|
|
bar_index);
|
|
|
|
//
|
|
result = IsBullishCandle(candle);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check a Candle is Bullish or not ...
|
|
bool IsBearishCandle(
|
|
XOHCL &candle // specified candle
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bool isValid = IsValid(candle);
|
|
if (!isValid)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = candle.open > candle.close;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool IsBearishCandle(
|
|
int bar_index // candle index
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
XOHCL candle = GetCandle(bar_index);
|
|
|
|
//
|
|
result = IsBearishCandle(candle);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool IsBearishCandle(
|
|
string symbol, // specify symbol
|
|
ENUM_TIMEFRAMES mPeriod, // specify timeframe
|
|
int bar_index // candle index
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
XOHCL candle = GetCandle(
|
|
symbol,
|
|
mPeriod,
|
|
bar_index);
|
|
|
|
//
|
|
result = IsBearishCandle(candle);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Applied Price at Specific Candle ...
|
|
double GetAppliedPrice(
|
|
XOHCL &candle, // specified candle
|
|
ENUM_APPLIED_PRICE source = PRICE_CLOSE // specified Applied To
|
|
)
|
|
{
|
|
//
|
|
double result = EMPTY_VALUE;
|
|
|
|
//
|
|
switch (source)
|
|
{
|
|
//
|
|
// Open ...
|
|
case PRICE_OPEN:
|
|
result = candle.open;
|
|
break;
|
|
|
|
//
|
|
// High ...
|
|
case PRICE_HIGH:
|
|
result = candle.high;
|
|
break;
|
|
|
|
//
|
|
// Low ...
|
|
case PRICE_LOW:
|
|
result = candle.low;
|
|
break;
|
|
|
|
//
|
|
// Median ((High + Low) / 2) ...
|
|
case PRICE_MEDIAN:
|
|
result = (candle.high + candle.low) / 2;
|
|
break;
|
|
|
|
//
|
|
// Typical ((High + Low + Close)/3) ...
|
|
case PRICE_TYPICAL:
|
|
result = (candle.high + candle.low + candle.close) / 3;
|
|
break;
|
|
|
|
//
|
|
// Weighted ((High + Low + Close + Close)/4) ...
|
|
case PRICE_WEIGHTED:
|
|
result = (candle.high + candle.low + (candle.close * 2)) / 4;
|
|
break;
|
|
|
|
//
|
|
// Close ...
|
|
default:
|
|
case PRICE_CLOSE:
|
|
result = candle.close;
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
double GetAppliedPrice(
|
|
int bar_index, // specify candle index
|
|
ENUM_APPLIED_PRICE source = PRICE_CLOSE // specified Applied To
|
|
)
|
|
{
|
|
//
|
|
double result = EMPTY_VALUE;
|
|
|
|
//
|
|
XOHCL candle = GetCandle(bar_index);
|
|
result = GetAppliedPrice(candle, source);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
double GetAppliedPrice(
|
|
int bar_index, // specify candle index
|
|
ENUM_SERIESMODE mode // converts Series Mode to Applied Price ...
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
ENUM_APPLIED_PRICE mAppliedTo = To(mode);
|
|
result = GetAppliedPrice(
|
|
bar_index,
|
|
mAppliedTo);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
template <typename T>
|
|
double GetAppliedPrice(ENUM_APPLIED_PRICE tprice, T &open[], T &high[], T &low[], T &close[], int i)
|
|
{
|
|
switch (tprice)
|
|
{
|
|
case PRICE_CLOSE:
|
|
return (close[i]);
|
|
case PRICE_OPEN:
|
|
return (open[i]);
|
|
case PRICE_HIGH:
|
|
return (high[i]);
|
|
case PRICE_LOW:
|
|
return (low[i]);
|
|
case PRICE_MEDIAN:
|
|
return ((high[i] + low[i]) / 2.0);
|
|
case PRICE_TYPICAL:
|
|
return ((high[i] + low[i] + close[i]) / 3.0);
|
|
case PRICE_WEIGHTED:
|
|
return ((high[i] + low[i] + close[i] + close[i]) / 4.0);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
//
|
|
// Converts ...
|
|
ENUM_APPLIED_PRICE To(
|
|
ENUM_SERIESMODE mode // converts Series Mode to Applied Price ...
|
|
)
|
|
{
|
|
//
|
|
ENUM_APPLIED_PRICE result = PRICE_CLOSE;
|
|
|
|
//
|
|
switch (mode)
|
|
{
|
|
//
|
|
// High ...
|
|
case MODE_HIGH:
|
|
result = PRICE_HIGH;
|
|
break;
|
|
|
|
//
|
|
// Open ...
|
|
case MODE_OPEN:
|
|
result = PRICE_OPEN;
|
|
break;
|
|
|
|
//
|
|
// Low ...
|
|
case MODE_LOW:
|
|
result = PRICE_LOW;
|
|
break;
|
|
|
|
//
|
|
// Close ...
|
|
// Default ...
|
|
case MODE_CLOSE:
|
|
default:
|
|
result = PRICE_CLOSE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve a Candel Data ...
|
|
XOHCL GetCandle(int bar_index)
|
|
{
|
|
//
|
|
XOHCL result = {};
|
|
|
|
//
|
|
double open = iOpen(_Symbol, _Period, bar_index);
|
|
double high = iHigh(_Symbol, _Period, bar_index);
|
|
double close = iClose(_Symbol, _Period, bar_index);
|
|
double low = iLow(_Symbol, _Period, bar_index);
|
|
|
|
//
|
|
result.low = low;
|
|
result.open = open;
|
|
result.high = high;
|
|
result.close = close;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
XOHCL GetCandle(
|
|
ENUM_TIMEFRAMES mPeriod, // specify timeframe
|
|
int bar_index // specify candle index
|
|
)
|
|
{
|
|
//
|
|
XOHCL result = {};
|
|
|
|
//
|
|
double open = iOpen(_Symbol, mPeriod, bar_index);
|
|
double high = iHigh(_Symbol, mPeriod, bar_index);
|
|
double close = iClose(_Symbol, mPeriod, bar_index);
|
|
double low = iLow(_Symbol, mPeriod, bar_index);
|
|
|
|
//
|
|
result.low = low;
|
|
result.open = open;
|
|
result.high = high;
|
|
result.close = close;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
XOHCL GetCandle(
|
|
string symbol, // specify symbol
|
|
ENUM_TIMEFRAMES mPeriod, // specify timeframe
|
|
int bar_index // specify candle index
|
|
)
|
|
{
|
|
//
|
|
XOHCL result = {};
|
|
|
|
//
|
|
double open = iOpen(symbol, mPeriod, bar_index);
|
|
double high = iHigh(symbol, mPeriod, bar_index);
|
|
double close = iClose(symbol, mPeriod, bar_index);
|
|
double low = iLow(symbol, mPeriod, bar_index);
|
|
|
|
//
|
|
result.low = low;
|
|
result.open = open;
|
|
result.high = high;
|
|
result.close = close;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get a Series Of Candles ...
|
|
bool GetCandles(
|
|
XOHCL &result[], // Hold Result ...
|
|
string mSymbol = NULL, // Specified Symbol ...
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Specified Period ...
|
|
int mStart = 0, // Start Bar Index ...
|
|
int mCount = 1 // Specified Number of Candles ...
|
|
)
|
|
{
|
|
//
|
|
bool mResult = false;
|
|
|
|
//
|
|
if (mStart < 0)
|
|
{
|
|
mStart = 0;
|
|
}
|
|
|
|
//
|
|
if (mCount <= 0)
|
|
{
|
|
mCount = 1;
|
|
}
|
|
|
|
//
|
|
Clean(result);
|
|
|
|
//
|
|
for (int i = mStart; i < mStart + mCount; i++)
|
|
{
|
|
//
|
|
XOHCL iC = GetCandle(
|
|
mSymbol,
|
|
mPeriod,
|
|
i);
|
|
|
|
//
|
|
Add(
|
|
iC,
|
|
result);
|
|
}
|
|
|
|
//
|
|
mResult = ArraySize(result) > 0;
|
|
|
|
//
|
|
return mResult;
|
|
}
|
|
|
|
//
|
|
// Retrieve a candle index in current timeframe inside another timeframe ...
|
|
int GetCandleBarIndex(
|
|
int bar_index, // Specify Candle index in current timeframe
|
|
ENUM_TIMEFRAMES destPeriod // Specify destination timeframe
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
datetime barTime = iTime(_Symbol, _Period, bar_index);
|
|
result = iBarShift(_Symbol, destPeriod, barTime);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve a symbol candle index in source time frame inside dest timeframe ...
|
|
int GetCandleBarIndex(
|
|
int bar_index, // Specify Candle index in current timeframe
|
|
string symbol, // Specify desired Symbol
|
|
ENUM_TIMEFRAMES sourcePeriod, // Specify bar_index timeframe
|
|
ENUM_TIMEFRAMES destPeriod // Specify destination timeframe
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
datetime barTime = iTime(symbol, sourcePeriod, bar_index);
|
|
result = iBarShift(symbol, destPeriod, barTime);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Determines a cnadle is Swing High
|
|
// or Swing Low order block ...
|
|
ENUM_X_SWING_TYPE GetCandleSwing(int bar_index)
|
|
{
|
|
//
|
|
ENUM_X_SWING_TYPE result = X_NO_SWING;
|
|
|
|
//
|
|
// Reading Candle Models ...
|
|
XOHCL candles[3];
|
|
candles[0] = GetCandle(bar_index + 1);
|
|
candles[1] = GetCandle(bar_index + 2);
|
|
candles[2] = GetCandle(bar_index + 3);
|
|
|
|
//
|
|
// Check Swing Start Candle has Strong Body ...
|
|
bool isStrongBodyCandle = CandleHasStrongBody(candles[2]);
|
|
if (!isStrongBodyCandle)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Swing Low Conditions ...
|
|
bool isSwingLowOrderBlock =
|
|
candles[2].low < candles[1].low &&
|
|
candles[1].low < candles[0].low &&
|
|
candles[2].low < candles[0].low;
|
|
if (isSwingLowOrderBlock)
|
|
{
|
|
result = X_SWING_LOW;
|
|
}
|
|
|
|
//
|
|
// Check Swing High Conditions ...
|
|
bool isSwingHighOrderBlock =
|
|
candles[2].high > candles[1].high &&
|
|
candles[1].high > candles[0].high &&
|
|
candles[2].high > candles[0].high;
|
|
if (isSwingHighOrderBlock)
|
|
{
|
|
result = X_SWING_HIGH;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
ENUM_X_SWING_TYPE GetCandleSwing(
|
|
ENUM_TIMEFRAMES mPeriod, // specify timeframe
|
|
int bar_index // specify candle index
|
|
)
|
|
{
|
|
//
|
|
ENUM_X_SWING_TYPE result = X_NO_SWING;
|
|
|
|
//
|
|
// Reading Candle Models ...
|
|
XOHCL candles[3];
|
|
candles[0] = GetCandle(mPeriod, bar_index + 1);
|
|
candles[1] = GetCandle(mPeriod, bar_index + 2);
|
|
candles[2] = GetCandle(mPeriod, bar_index + 3);
|
|
|
|
//
|
|
// Check Swing Start Candle has Strong Body ...
|
|
bool isStrongBodyCandle = CandleHasStrongBody(candles[2]);
|
|
if (!isStrongBodyCandle)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Swing Low Conditions ...
|
|
bool isSwingLowOrderBlock =
|
|
candles[2].low < candles[1].low &&
|
|
candles[1].low < candles[0].low &&
|
|
candles[2].low < candles[0].low;
|
|
if (isSwingLowOrderBlock)
|
|
{
|
|
result = X_SWING_LOW;
|
|
}
|
|
|
|
//
|
|
// Check Swing High Conditions ...
|
|
bool isSwingHighOrderBlock =
|
|
candles[2].high > candles[1].high &&
|
|
candles[1].high > candles[0].high &&
|
|
candles[2].high > candles[0].high;
|
|
if (isSwingHighOrderBlock)
|
|
{
|
|
result = X_SWING_HIGH;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
ENUM_X_SWING_TYPE GetCandleSwing(
|
|
string symbol, // specify symbol
|
|
ENUM_TIMEFRAMES mPeriod, // specify timeframe
|
|
int bar_index // specify candle index
|
|
)
|
|
{
|
|
//
|
|
ENUM_X_SWING_TYPE result = X_NO_SWING;
|
|
|
|
//
|
|
// Reading Candle Models ...
|
|
XOHCL candles[3];
|
|
candles[0] = GetCandle(symbol, mPeriod, bar_index + 1);
|
|
candles[1] = GetCandle(symbol, mPeriod, bar_index + 2);
|
|
candles[2] = GetCandle(symbol, mPeriod, bar_index + 3);
|
|
|
|
//
|
|
// Check Swing Start Candle has Strong Body ...
|
|
bool isStrongBodyCandle = CandleHasStrongBody(candles[2]);
|
|
if (!isStrongBodyCandle)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Swing Low Conditions ...
|
|
bool isSwingLowOrderBlock =
|
|
candles[2].low < candles[1].low &&
|
|
candles[1].low < candles[0].low &&
|
|
candles[2].low < candles[0].low;
|
|
if (isSwingLowOrderBlock)
|
|
{
|
|
result = X_SWING_LOW;
|
|
}
|
|
|
|
//
|
|
// Check Swing High Conditions ...
|
|
bool isSwingHighOrderBlock =
|
|
candles[2].high > candles[1].high &&
|
|
candles[1].high > candles[0].high &&
|
|
candles[2].high > candles[0].high;
|
|
if (isSwingHighOrderBlock)
|
|
{
|
|
result = X_SWING_HIGH;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Swing Points ...
|
|
int FindSwing(
|
|
string mSymbol, // Trading Symbol ...
|
|
ENUM_TIMEFRAMES mPeriod, // Trading Period ...
|
|
ENUM_SERIESMODE mode, // Swing Based On Price mode ...
|
|
int mLength, // Loopback ...
|
|
int bar_index // BarIndex ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (StringLen(mSymbol) == 0 || (mode != MODE_HIGH && mode != MODE_LOW))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int current = bar_index;
|
|
int founded = FindNextSwing(
|
|
mSymbol,
|
|
mPeriod,
|
|
mode,
|
|
(mLength * 2) + 1,
|
|
current - mLength);
|
|
|
|
//
|
|
while (founded != current)
|
|
{
|
|
//
|
|
current = FindNextSwing(
|
|
mSymbol,
|
|
mPeriod,
|
|
mode,
|
|
mLength,
|
|
current + 1);
|
|
|
|
//
|
|
founded = FindNextSwing(
|
|
mSymbol,
|
|
mPeriod,
|
|
mode,
|
|
(mLength * 2) + 1,
|
|
current - mLength);
|
|
}
|
|
|
|
//
|
|
result = current;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Next Swing ...
|
|
int FindNextSwing(
|
|
string mSymbol, // Trading Symbol ...
|
|
ENUM_TIMEFRAMES mPeriod, // Trading Period ...
|
|
ENUM_SERIESMODE mode, // Swing Based On Price mode ...
|
|
int mLength, // Loopback ...
|
|
int bar_index // BarIndex ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (bar_index < 0)
|
|
{
|
|
mLength += bar_index;
|
|
bar_index = 0;
|
|
}
|
|
|
|
//
|
|
result = mode == MODE_HIGH
|
|
? iHighest(
|
|
mSymbol,
|
|
mPeriod,
|
|
mode,
|
|
mLength,
|
|
bar_index)
|
|
: iLowest(
|
|
mSymbol,
|
|
mPeriod,
|
|
mode,
|
|
mLength,
|
|
bar_index);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Market Highest High ...
|
|
double GetHighestHigh(
|
|
int mLength, // Which market Length use
|
|
int bar_index // bar index
|
|
)
|
|
{
|
|
//
|
|
double result = -1;
|
|
|
|
//
|
|
int rIdx = iHighest(
|
|
_Symbol,
|
|
_Period,
|
|
MODE_HIGH,
|
|
mLength,
|
|
bar_index);
|
|
|
|
//
|
|
result = iHigh(
|
|
_Symbol,
|
|
_Period,
|
|
rIdx);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
double GetHighestHigh(
|
|
int mLength, // Which market Length use
|
|
int bar_index, // bar index
|
|
ENUM_SERIESMODE mode // Calculation mode
|
|
)
|
|
{
|
|
//
|
|
double result = -1;
|
|
|
|
//
|
|
int rIdx = iHighest(
|
|
_Symbol,
|
|
_Period,
|
|
mode,
|
|
mLength,
|
|
bar_index);
|
|
|
|
//
|
|
result = iHigh(
|
|
_Symbol,
|
|
_Period,
|
|
rIdx);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
double GetHighestHigh(
|
|
string symbol, // Specified Symbol
|
|
ENUM_TIMEFRAMES mPeriod, // Specified Period
|
|
int mLength, // Which market Length use
|
|
int bar_index // bar index
|
|
)
|
|
{
|
|
//
|
|
double result = -1;
|
|
|
|
//
|
|
int rIdx = iHighest(
|
|
symbol,
|
|
mPeriod,
|
|
MODE_HIGH,
|
|
mLength,
|
|
bar_index);
|
|
|
|
//
|
|
result = iHigh(
|
|
symbol,
|
|
mPeriod,
|
|
rIdx);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
double GetHighestHigh(
|
|
string symbol, // Specified Symbol
|
|
ENUM_TIMEFRAMES mPeriod, // Specified Period
|
|
ENUM_SERIESMODE mode, // Calculation mode
|
|
int mLength, // Which market Length use
|
|
int bar_index // bar index
|
|
)
|
|
{
|
|
//
|
|
double result = -1;
|
|
|
|
//
|
|
int rIdx = iHighest(
|
|
symbol,
|
|
mPeriod,
|
|
mode,
|
|
mLength,
|
|
bar_index);
|
|
|
|
//
|
|
result = iHigh(
|
|
symbol,
|
|
mPeriod,
|
|
rIdx);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Market Lowest Low ...
|
|
double GetLowestLow(
|
|
int mLength, // Which market Length use
|
|
int bar_index // bar index
|
|
)
|
|
{
|
|
//
|
|
double result = -1;
|
|
|
|
//
|
|
int rIdx = iLowest(
|
|
_Symbol,
|
|
_Period,
|
|
MODE_LOW,
|
|
mLength,
|
|
bar_index);
|
|
|
|
//
|
|
result = iLow(
|
|
_Symbol,
|
|
_Period,
|
|
rIdx);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
double GetLowestLow(
|
|
int mLength, // Which market Length use
|
|
int bar_index, // bar index
|
|
ENUM_SERIESMODE mode // Calculation mode
|
|
)
|
|
{
|
|
//
|
|
double result = -1;
|
|
|
|
//
|
|
int rIdx = iLowest(
|
|
_Symbol,
|
|
_Period,
|
|
mode,
|
|
mLength,
|
|
bar_index);
|
|
|
|
//
|
|
result = iLow(
|
|
_Symbol,
|
|
_Period,
|
|
rIdx);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
double GetLowestLow(
|
|
string symbol, // Specified Symbol
|
|
ENUM_TIMEFRAMES mPeriod, // Specified Period
|
|
int mLength, // Which market Length use
|
|
int bar_index // bar index
|
|
)
|
|
{
|
|
//
|
|
double result = -1;
|
|
|
|
//
|
|
int rIdx = iLowest(
|
|
symbol,
|
|
mPeriod,
|
|
MODE_LOW,
|
|
mLength,
|
|
bar_index);
|
|
|
|
//
|
|
result = iLow(
|
|
symbol,
|
|
mPeriod,
|
|
rIdx);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
double GetLowestLow(
|
|
string symbol, // Specified Symbol
|
|
ENUM_TIMEFRAMES mPeriod, // Specified Period
|
|
ENUM_SERIESMODE mode, // Calculation mode
|
|
int mLength, // Which market Length use
|
|
int bar_index // bar index
|
|
)
|
|
{
|
|
//
|
|
double result = -1;
|
|
|
|
//
|
|
int rIdx = iLowest(
|
|
symbol,
|
|
mPeriod,
|
|
mode,
|
|
mLength,
|
|
bar_index);
|
|
|
|
//
|
|
result = iLow(
|
|
symbol,
|
|
mPeriod,
|
|
rIdx);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Support and Resistance for Specific Bar based on provided Buffer ...
|
|
XOHCLSupRes ExtractSupportAndResistance(
|
|
int barIndex, // Bar Index ...
|
|
const double &pivots[], // Provided Pivot Points ...
|
|
int count = 3, // Number of Requireds ...
|
|
double step = 0, // Distance between each item with it's Last Side ...
|
|
string mSymbol = NULL, // Trading Symbol ...
|
|
ENUM_TIMEFRAMES mPeriod = NULL // Trading Period ...
|
|
)
|
|
{
|
|
//
|
|
if (StringLen(mSymbol) == 0 || mSymbol == NULL)
|
|
{
|
|
mSymbol = _Symbol;
|
|
}
|
|
|
|
//
|
|
if (mPeriod == NULL)
|
|
{
|
|
mPeriod = _Period;
|
|
}
|
|
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
XOHCLSupRes result;
|
|
Clean(result.res);
|
|
Clean(result.sup);
|
|
|
|
//
|
|
int pivotsCount = ArraySize(pivots);
|
|
if (pivotsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (count <= 0 ||
|
|
count > pivotsCount - 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL cBar = GetCandle(
|
|
mSymbol,
|
|
mPeriod,
|
|
barIndex);
|
|
|
|
//
|
|
double lastR = 0;
|
|
double tmpR[];
|
|
|
|
//
|
|
double lastS = 0;
|
|
double tmpS[];
|
|
|
|
//
|
|
// Extract Supports ...
|
|
// which prices is under low of candle ...
|
|
//
|
|
// Extract Resistance ...
|
|
// which prices is over high of candle ...
|
|
for (int i = 0; i < pivotsCount; i++)
|
|
{
|
|
//
|
|
double iFlat = pivots[i];
|
|
|
|
//
|
|
if (iFlat > cBar.high)
|
|
{
|
|
//
|
|
bool canAdd =
|
|
step <= 0
|
|
? true
|
|
: lastR == 0 || MathAbs(iFlat - lastR) >= step;
|
|
if (canAdd)
|
|
{
|
|
//
|
|
Add(
|
|
iFlat,
|
|
tmpR);
|
|
|
|
//
|
|
lastR = iFlat;
|
|
}
|
|
}
|
|
else if (iFlat < cBar.low)
|
|
{
|
|
//
|
|
bool canAdd =
|
|
step <= 0
|
|
? true
|
|
: lastS == 0 || MathAbs(iFlat - lastS) >= step;
|
|
if (canAdd)
|
|
{
|
|
//
|
|
Add(
|
|
iFlat,
|
|
tmpS);
|
|
|
|
//
|
|
lastS = iFlat;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Sorting Founded Resistance and Supports ...
|
|
|
|
//
|
|
// Since Resistance Levels must be Increasing ...
|
|
ArraySort(tmpR);
|
|
|
|
//
|
|
// Since Support Levels must be Decreasing ...
|
|
ArraySort(tmpS);
|
|
ArrayReverse(tmpS);
|
|
|
|
//
|
|
// Fill Resistance ...
|
|
int tmpRCount = ArraySize(tmpR);
|
|
if (tmpRCount > 0)
|
|
{
|
|
//
|
|
if (tmpRCount < count)
|
|
{
|
|
//
|
|
ArrayCopy(
|
|
result.res,
|
|
tmpR);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
ArrayCopy(
|
|
result.res,
|
|
tmpR,
|
|
0,
|
|
0,
|
|
count);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Fill Supports ...
|
|
int tmpSCount = ArraySize(tmpS);
|
|
if (tmpSCount > 0)
|
|
{
|
|
//
|
|
if (tmpSCount < count)
|
|
{
|
|
//
|
|
ArrayCopy(
|
|
result.sup,
|
|
tmpS);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
ArrayCopy(
|
|
result.sup,
|
|
tmpS,
|
|
0,
|
|
0,
|
|
count);
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Support and Resistance for Specific Price based on provided Buffer ...
|
|
XOHCLSupRes ExtractSupportAndResistance(
|
|
double price, // Price ...
|
|
const double &pivots[], // Provided Pivot Points ...
|
|
int count = 3, // Number of Requireds ...
|
|
double step = 0 // Distance between each item with it's Last Side ...
|
|
)
|
|
{
|
|
//
|
|
XOHCLSupRes result;
|
|
Clean(result.res);
|
|
Clean(result.sup);
|
|
|
|
//
|
|
if (price <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int pivotsCount = ArraySize(pivots);
|
|
if (pivotsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (count <= 0 ||
|
|
count > pivotsCount - 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double lastR = 0;
|
|
double tmpR[];
|
|
|
|
//
|
|
double lastS = 0;
|
|
double tmpS[];
|
|
|
|
//
|
|
// Extract Supports ...
|
|
// which prices is under low of candle ...
|
|
//
|
|
// Extract Resistance ...
|
|
// which prices is over high of candle ...
|
|
for (int i = 0; i < pivotsCount; i++)
|
|
{
|
|
//
|
|
double iFlat = pivots[i];
|
|
|
|
//
|
|
if (iFlat > price)
|
|
{
|
|
//
|
|
bool canAdd =
|
|
step <= 0
|
|
? true
|
|
: lastR == 0 || MathAbs(iFlat - lastR) >= step;
|
|
if (canAdd)
|
|
{
|
|
//
|
|
Add(
|
|
iFlat,
|
|
tmpR);
|
|
|
|
//
|
|
lastR = iFlat;
|
|
}
|
|
}
|
|
else if (iFlat < price)
|
|
{
|
|
//
|
|
bool canAdd =
|
|
step <= 0
|
|
? true
|
|
: lastS == 0 || MathAbs(iFlat - lastS) >= step;
|
|
if (canAdd)
|
|
{
|
|
//
|
|
Add(
|
|
iFlat,
|
|
tmpS);
|
|
|
|
//
|
|
lastS = iFlat;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Sorting Founded Resistance and Supports ...
|
|
|
|
//
|
|
// Since Resistance Levels must be Increasing ...
|
|
ArraySort(tmpR);
|
|
|
|
//
|
|
// Since Support Levels must be Decreasing ...
|
|
ArraySort(tmpS);
|
|
ArrayReverse(tmpS);
|
|
|
|
//
|
|
// Fill Resistance ...
|
|
int tmpRCount = ArraySize(tmpR);
|
|
if (tmpRCount > 0)
|
|
{
|
|
//
|
|
if (tmpRCount < count)
|
|
{
|
|
//
|
|
ArrayCopy(
|
|
result.res,
|
|
tmpR);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
ArrayCopy(
|
|
result.res,
|
|
tmpR,
|
|
0,
|
|
0,
|
|
count);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Fill Supports ...
|
|
int tmpSCount = ArraySize(tmpS);
|
|
if (tmpSCount > 0)
|
|
{
|
|
//
|
|
if (tmpSCount < count)
|
|
{
|
|
//
|
|
ArrayCopy(
|
|
result.sup,
|
|
tmpS);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
ArrayCopy(
|
|
result.sup,
|
|
tmpS,
|
|
0,
|
|
0,
|
|
count);
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find a Value less than Specified ...
|
|
double FindLesserThanValue(
|
|
double value, // Specified Value ...
|
|
const double &source[], // Source ...
|
|
bool isDescend = false // Find Biggest Lesser Value ...
|
|
)
|
|
{
|
|
//
|
|
double result = -1;
|
|
|
|
//
|
|
int itemsCount = ArraySize(source);
|
|
if (itemsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Make a Copy of source ...
|
|
double tmp[];
|
|
|
|
//
|
|
ArrayResize(
|
|
tmp,
|
|
ArraySize(source));
|
|
|
|
//
|
|
ArrayCopy(
|
|
tmp,
|
|
source);
|
|
|
|
//
|
|
// Sort Temp Buffer ...
|
|
ArraySort(tmp);
|
|
if (isDescend)
|
|
{
|
|
ArrayReverse(tmp);
|
|
}
|
|
|
|
//
|
|
int tmpCount = ArraySize(tmp);
|
|
for (int i = 0; i < tmpCount; i++)
|
|
{
|
|
//
|
|
double iValue = tmp[i];
|
|
|
|
//
|
|
if (iValue < value)
|
|
{
|
|
//
|
|
result = iValue;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find a Value less than Specified ...
|
|
double FindBiggerThanValue(
|
|
double value, // Specified Value ...
|
|
const double &source[], // Source ...
|
|
bool isDescend = false // Find Smallest Bigger Value ...
|
|
)
|
|
{
|
|
//
|
|
double result = -1;
|
|
|
|
//
|
|
int itemsCount = ArraySize(source);
|
|
if (itemsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Make a Copy of source ...
|
|
double tmp[];
|
|
|
|
//
|
|
ArrayResize(
|
|
tmp,
|
|
ArraySize(source));
|
|
|
|
//
|
|
ArrayCopy(
|
|
tmp,
|
|
source);
|
|
|
|
//
|
|
// Sort Temp Buffer ...
|
|
ArraySort(tmp);
|
|
if (!isDescend)
|
|
{
|
|
ArrayReverse(tmp);
|
|
}
|
|
|
|
//
|
|
int tmpCount = ArraySize(tmp);
|
|
for (int i = 0; i < tmpCount; i++)
|
|
{
|
|
//
|
|
double iValue = tmp[i];
|
|
|
|
//
|
|
if (iValue > value)
|
|
{
|
|
//
|
|
result = iValue;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Fib Level ...
|
|
double GetFibonacciLevel(
|
|
double upPrice,
|
|
double downPrice,
|
|
double level,
|
|
int direction)
|
|
{
|
|
//
|
|
double ling = upPrice - downPrice;
|
|
double pLevel = (ling / 100) * (level * 100);
|
|
|
|
//
|
|
double result = direction > 0 ? upPrice - pLevel : downPrice + pLevel;
|
|
result = NormalizeDouble(result, _Digits);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check first Cross Over second at bar_index ...
|
|
bool IsCrossOver(
|
|
const double &first[], // the buffer which check crossing over second buffer
|
|
const double &second[], // first buffer checks based on this buffer
|
|
const int bar_index // check crosses in specific index
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
ArraySetAsSeries(first, true);
|
|
ArraySetAsSeries(second, true);
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (ArraySize(first) < bar_index + 1 || ArraySize(second) < bar_index + 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = first[bar_index] > second[bar_index] &&
|
|
!(first[bar_index + 1] > second[bar_index + 1]);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check first is Over second at bar_index ...
|
|
bool IsOver(
|
|
const double &first[], // the buffer which check over second buffer
|
|
const double &second[], // first buffer checks based on this buffer
|
|
const int bar_index // check crosses in specific index
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
ArraySetAsSeries(first, true);
|
|
ArraySetAsSeries(second, true);
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (ArraySize(first) < bar_index + 1 || ArraySize(second) < bar_index + 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = first[bar_index] > second[bar_index] &&
|
|
first[bar_index + 1] > second[bar_index + 1];
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check first Cross Under second at bar_index ...
|
|
bool IsCrossUnder(
|
|
const double &first[], // the buffer which check crossing under second buffer
|
|
const double &second[], // first buffer checks based on this buffer
|
|
const int bar_index // check crosses in specific index
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
ArraySetAsSeries(first, true);
|
|
ArraySetAsSeries(second, true);
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (ArraySize(first) < bar_index + 1 || ArraySize(second) < bar_index + 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = first[bar_index] < second[bar_index] &&
|
|
!(first[bar_index + 1] < second[bar_index + 1]);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check first is Under second at bar_index ...
|
|
bool IsUnder(
|
|
const double &first[], // the buffer which check under second buffer
|
|
const double &second[], // first buffer checks based on this buffer
|
|
const int bar_index // check crosses in specific index
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
ArraySetAsSeries(first, true);
|
|
ArraySetAsSeries(second, true);
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (ArraySize(first) < bar_index + 1 || ArraySize(second) < bar_index + 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = first[bar_index] < second[bar_index] &&
|
|
first[bar_index + 1] < second[bar_index + 1];
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Slope of Specified Buffer at Specified Index ...
|
|
double GetSlope(
|
|
int from, // In Past Index ...
|
|
int to, // In Past Index ...
|
|
double &buffer[])
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
double toValue = buffer[to];
|
|
double fromValue = buffer[from];
|
|
double deltaValue = toValue - fromValue;
|
|
double deltaTime = from - to;
|
|
|
|
//
|
|
result = deltaValue / deltaTime;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check if a Value Increasing in Loopback ...
|
|
bool IsIncreasing(
|
|
int from, // Last Time Index
|
|
int to, // Fisr Tima Index
|
|
double &buffer[] // the Buffer which required to search
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (
|
|
from <= to ||
|
|
ArraySize(buffer) < from + 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Loop through Items ...
|
|
double toValue = buffer[to];
|
|
double fromValue = buffer[from];
|
|
result = toValue > fromValue;
|
|
for (int i = to + 1; i <= from - 1; i++)
|
|
{
|
|
//
|
|
double iValue = buffer[i];
|
|
bool isPassed = toValue >= iValue;
|
|
|
|
//
|
|
bool isIIncreasing = IsIncreasing(
|
|
from,
|
|
i,
|
|
buffer);
|
|
|
|
//
|
|
// Check Result ...
|
|
result = result && isPassed && isIIncreasing;
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check if a Value Decreasing in Loopback ...
|
|
bool IsDecreasing(
|
|
int from, // Last Time Index
|
|
int to, // Fisr Tima Index
|
|
double &buffer[] // the Buffer which required to search
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (
|
|
from <= to ||
|
|
ArraySize(buffer) < from + 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Loop through Items ...
|
|
double toValue = buffer[to];
|
|
double fromValue = buffer[from];
|
|
result = toValue < fromValue;
|
|
for (int i = to + 1; i <= from - 1; i++)
|
|
{
|
|
//
|
|
double iValue = buffer[i];
|
|
bool isPassed = toValue <= iValue;
|
|
|
|
//
|
|
bool isIDecreasing = IsDecreasing(
|
|
from,
|
|
i,
|
|
buffer);
|
|
|
|
//
|
|
// Check Result ...
|
|
result = result && isPassed && isIDecreasing;
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Max Value of Specific Loopback of a Buffer ...
|
|
double GetMaxValue(
|
|
int mLoopback, // loopback length
|
|
double &buffer[] // the Buffer which required to search
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (
|
|
mLoopback < 2 ||
|
|
ArraySize(buffer) < mLoopback)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Loop Through LoopBack ...
|
|
for (int i = 0; i < mLoopback; i++)
|
|
{
|
|
//
|
|
double iValue = buffer[i];
|
|
|
|
//
|
|
result =
|
|
//
|
|
result == 0 || result < iValue
|
|
//
|
|
? iValue
|
|
//
|
|
: result
|
|
//
|
|
;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Min Value of Specific Loopback of a Buffer ...
|
|
double GetMinValue(
|
|
int mLoopback, // loopback length
|
|
double &buffer[] // the Buffer which required to search
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (
|
|
mLoopback < 2 ||
|
|
ArraySize(buffer) < mLoopback)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Loop Through LoopBack ...
|
|
for (int i = 0; i < mLoopback; i++)
|
|
{
|
|
//
|
|
double iValue = buffer[i];
|
|
|
|
//
|
|
result =
|
|
//
|
|
result == 0 || result > iValue
|
|
//
|
|
? iValue
|
|
//
|
|
: result
|
|
//
|
|
;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Same Values in Array ...
|
|
void FindSameValueInBuffer(
|
|
double &result[], // Holds Result ...
|
|
double &source[], // Source ...
|
|
int verifications = 3 // Number of Consequence Repeat ...
|
|
)
|
|
{
|
|
//
|
|
Clean(result);
|
|
|
|
//
|
|
// TenkanSen Flats ...
|
|
int sourceCount = ArraySize(source);
|
|
if (sourceCount > verifications)
|
|
{
|
|
//
|
|
double mLast = 0;
|
|
int mVerified = 0;
|
|
for (int i = 0; i < sourceCount; i++)
|
|
{
|
|
//
|
|
double iVal = source[i];
|
|
if (mLast == 0)
|
|
{
|
|
mLast = iVal;
|
|
}
|
|
else if (mLast == iVal)
|
|
{
|
|
mVerified++;
|
|
}
|
|
else
|
|
{
|
|
mLast = iVal;
|
|
mVerified = 0;
|
|
}
|
|
|
|
//
|
|
if (iVal == mLast && mVerified >= verifications)
|
|
{
|
|
//
|
|
Add(
|
|
iVal,
|
|
result);
|
|
|
|
//
|
|
mLast = 0;
|
|
mVerified = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
bool IsInPeak(
|
|
int mLoopback, // loopback length
|
|
double &buffer[] // the Buffer which required to search
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (
|
|
mLoopback < 2 ||
|
|
ArraySize(buffer) < mLoopback + 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int q1Length = mLoopback / 4;
|
|
int halfLength = mLoopback / 2;
|
|
int q2Length = halfLength + q1Length;
|
|
|
|
//
|
|
double firstValue = buffer[1];
|
|
double q1Value = buffer[q1Length];
|
|
double q2Value = buffer[q2Length];
|
|
double halfValue = buffer[halfLength];
|
|
double lastValue = buffer[ArraySize(buffer) - 1];
|
|
|
|
//
|
|
// Peak ...
|
|
result =
|
|
//
|
|
firstValue > lastValue
|
|
//
|
|
&&
|
|
//
|
|
(
|
|
firstValue > q1Value &&
|
|
firstValue > halfValue)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool IsInVale(
|
|
int mLoopback, // loopback length
|
|
double &buffer[] // the Buffer which required to search
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (
|
|
mLoopback < 2 ||
|
|
ArraySize(buffer) < mLoopback + 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int q1Length = mLoopback / 4;
|
|
int halfLength = mLoopback / 2;
|
|
int q2Length = halfLength + q1Length;
|
|
|
|
//
|
|
double firstValue = buffer[1];
|
|
double q1Value = buffer[q1Length];
|
|
double q2Value = buffer[q2Length];
|
|
double halfValue = buffer[halfLength];
|
|
double lastValue = buffer[ArraySize(buffer) - 1];
|
|
|
|
//
|
|
// Peak ...
|
|
result =
|
|
//
|
|
firstValue < lastValue
|
|
//
|
|
&&
|
|
//
|
|
(
|
|
firstValue < q1Value &&
|
|
firstValue < halfValue)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Sharp Happens or not ...
|
|
bool IsSharpChanged(
|
|
double fromValue, // Past Value
|
|
double toValue, // Present Value
|
|
double maxValue, // Max in Range Value
|
|
double minValue // Min in Range Value
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// This Used In Increased or Decreased Sharp Detection ...
|
|
bool isIncreased = toValue > fromValue;
|
|
|
|
//
|
|
double toFromDelta = MathAbs(toValue - fromValue);
|
|
double minMaxDelta = maxValue - minValue;
|
|
|
|
//
|
|
result = toFromDelta >= (minMaxDelta / 3);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool IsSharpChanged(
|
|
int from, // Past Index in Series
|
|
int to, // Present Index in Series
|
|
double &buffer[] // the Buffer which required to search
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (
|
|
from <= to ||
|
|
ArraySize(buffer) < from + 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Loop through Items ...
|
|
double toValue = buffer[to];
|
|
double fromValue = buffer[from];
|
|
|
|
//
|
|
// This Used In Increased or Decreased Sharp Detection ...
|
|
bool isIncreased = toValue > fromValue;
|
|
|
|
//
|
|
double minValue = GetMinValue(
|
|
ArraySize(buffer) - 1,
|
|
buffer);
|
|
double maxValue = GetMaxValue(
|
|
ArraySize(buffer) - 1,
|
|
buffer);
|
|
double minMaxDelta = maxValue - minValue;
|
|
|
|
//
|
|
// Sharp Detection ...
|
|
result = IsSharpChanged(
|
|
fromValue,
|
|
toValue,
|
|
maxValue,
|
|
minValue);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool IsSharpChanged(
|
|
int from, // Past Bar Index
|
|
int to, // Present Bar Index
|
|
ENUM_APPLIED_PRICE appliedPrice // Which Price Choose in From or To
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
double toValue = GetAppliedPrice(
|
|
to,
|
|
appliedPrice);
|
|
double fromValue = GetAppliedPrice(
|
|
from,
|
|
appliedPrice);
|
|
|
|
//
|
|
int hIdx = iHighest(
|
|
_Symbol,
|
|
_Period,
|
|
MODE_HIGH,
|
|
from,
|
|
to);
|
|
double maxValue = iHigh(
|
|
_Symbol,
|
|
_Period,
|
|
hIdx);
|
|
|
|
//
|
|
int lIdx = iLowest(
|
|
_Symbol,
|
|
_Period,
|
|
MODE_LOW,
|
|
from,
|
|
to);
|
|
double minValue = iLow(
|
|
_Symbol,
|
|
_Period,
|
|
lIdx);
|
|
|
|
//
|
|
result = IsSharpChanged(
|
|
fromValue,
|
|
toValue,
|
|
maxValue,
|
|
minValue);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check InCreased Sharp Happens or not ...
|
|
bool IsSharpIncreasedChanged(
|
|
double fromValue, // Past Value
|
|
double toValue, // Present Value
|
|
double maxValue, // Max in Range Value
|
|
double minValue // Min in Range Value
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// This Used In Increased or Decreased Sharp Detection ...
|
|
bool isIncreased = toValue > fromValue;
|
|
|
|
//
|
|
double toFromDelta = MathAbs(toValue - fromValue);
|
|
double minMaxDelta = maxValue - minValue;
|
|
|
|
//
|
|
result =
|
|
isIncreased &&
|
|
toFromDelta >= (minMaxDelta / 3);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool IsSharpIncreasedChanged(
|
|
int from, // Past Index in Series
|
|
int to, // Present Index in Series
|
|
double &buffer[] // the Buffer which required to search
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (
|
|
from <= to ||
|
|
ArraySize(buffer) < from + 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Loop through Items ...
|
|
double toValue = buffer[to];
|
|
double fromValue = buffer[from];
|
|
|
|
//
|
|
double minValue = GetMinValue(
|
|
ArraySize(buffer) - 1,
|
|
buffer);
|
|
double maxValue = GetMaxValue(
|
|
ArraySize(buffer) - 1,
|
|
buffer);
|
|
double minMaxDelta = maxValue - minValue;
|
|
|
|
//
|
|
// Sharp Detection ...
|
|
result = IsSharpIncreasedChanged(
|
|
fromValue,
|
|
toValue,
|
|
maxValue,
|
|
minValue);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool IsSharpIncreasedChanged(
|
|
int from, // Past Bar Index
|
|
int to, // Present Bar Index
|
|
ENUM_APPLIED_PRICE appliedPrice // Which Price Choose in From or To
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
double toValue = GetAppliedPrice(
|
|
to,
|
|
appliedPrice);
|
|
double fromValue = GetAppliedPrice(
|
|
from,
|
|
appliedPrice);
|
|
|
|
//
|
|
int hIdx = iHighest(
|
|
_Symbol,
|
|
_Period,
|
|
MODE_HIGH,
|
|
from,
|
|
to);
|
|
double maxValue = iHigh(
|
|
_Symbol,
|
|
_Period,
|
|
hIdx);
|
|
|
|
//
|
|
int lIdx = iLowest(
|
|
_Symbol,
|
|
_Period,
|
|
MODE_LOW,
|
|
from,
|
|
to);
|
|
double minValue = iLow(
|
|
_Symbol,
|
|
_Period,
|
|
lIdx);
|
|
|
|
//
|
|
result = IsSharpIncreasedChanged(
|
|
fromValue,
|
|
toValue,
|
|
maxValue,
|
|
minValue);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Decreased Sharp Happens or not ...
|
|
bool IsSharpDecreasedChanged(
|
|
double fromValue, // Past Value
|
|
double toValue, // Present Value
|
|
double maxValue, // Max in Range Value
|
|
double minValue // Min in Range Value
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// This Used In Increased or Decreased Sharp Detection ...
|
|
bool isIncreased = toValue > fromValue;
|
|
|
|
//
|
|
double toFromDelta = MathAbs(toValue - fromValue);
|
|
double minMaxDelta = maxValue - minValue;
|
|
|
|
//
|
|
result =
|
|
!isIncreased &&
|
|
toFromDelta >= (minMaxDelta / 3);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool IsSharpDecreasedChanged(
|
|
int from, // Past Index in Series
|
|
int to, // Present Index in Series
|
|
double &buffer[] // the Buffer which required to search
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (
|
|
from <= to ||
|
|
ArraySize(buffer) < from + 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Loop through Items ...
|
|
double toValue = buffer[to];
|
|
double fromValue = buffer[from];
|
|
|
|
//
|
|
double minValue = GetMinValue(
|
|
ArraySize(buffer) - 1,
|
|
buffer);
|
|
double maxValue = GetMaxValue(
|
|
ArraySize(buffer) - 1,
|
|
buffer);
|
|
double minMaxDelta = maxValue - minValue;
|
|
|
|
//
|
|
// Sharp Detection ...
|
|
result = IsSharpDecreasedChanged(
|
|
fromValue,
|
|
toValue,
|
|
maxValue,
|
|
minValue);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool IsSharpDecreasedChanged(
|
|
int from, // Past Bar Index
|
|
int to, // Present Bar Index
|
|
ENUM_APPLIED_PRICE appliedPrice // Which Price Choose in From or To
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
double toValue = GetAppliedPrice(
|
|
to,
|
|
appliedPrice);
|
|
double fromValue = GetAppliedPrice(
|
|
from,
|
|
appliedPrice);
|
|
|
|
//
|
|
int hIdx = iHighest(
|
|
_Symbol,
|
|
_Period,
|
|
MODE_HIGH,
|
|
from,
|
|
to);
|
|
double maxValue = iHigh(
|
|
_Symbol,
|
|
_Period,
|
|
hIdx);
|
|
|
|
//
|
|
int lIdx = iLowest(
|
|
_Symbol,
|
|
_Period,
|
|
MODE_LOW,
|
|
from,
|
|
to);
|
|
double minValue = iLow(
|
|
_Symbol,
|
|
_Period,
|
|
lIdx);
|
|
|
|
//
|
|
result = IsSharpDecreasedChanged(
|
|
fromValue,
|
|
toValue,
|
|
maxValue,
|
|
minValue);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
void Clean(int &buffer[])
|
|
{
|
|
//
|
|
ArrayFree(buffer);
|
|
ArrayResize(buffer, 0);
|
|
}
|
|
void Clean(ulong &buffer[])
|
|
{
|
|
//
|
|
ArrayFree(buffer);
|
|
ArrayResize(buffer, 0);
|
|
}
|
|
void Clean(string &buffer[])
|
|
{
|
|
//
|
|
ArrayFree(buffer);
|
|
ArrayResize(buffer, 0);
|
|
}
|
|
void Clean(double &buffer[])
|
|
{
|
|
//
|
|
ArrayFree(buffer);
|
|
ArrayResize(buffer, 0);
|
|
}
|
|
|
|
//
|
|
template <typename T>
|
|
bool GetLastItem(
|
|
T &item, // Holds Result
|
|
T &buffer[] // Specified Buffer
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int bufferSize = ArraySize(buffer);
|
|
if (bufferSize <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
item = buffer[bufferSize - 1];
|
|
|
|
//
|
|
result = true;
|
|
return result;
|
|
}
|
|
|
|
//
|
|
void Add(
|
|
int item, // item want to add
|
|
int &buffer[] // Destination buffer
|
|
)
|
|
{
|
|
//
|
|
ArrayResize(
|
|
buffer,
|
|
ArraySize(buffer) + 1);
|
|
|
|
//
|
|
buffer[ArraySize(buffer) - 1] = item;
|
|
}
|
|
void Add(
|
|
ulong item, // item want to add
|
|
ulong &buffer[] // Destination buffer
|
|
)
|
|
{
|
|
//
|
|
ArrayResize(
|
|
buffer,
|
|
ArraySize(buffer) + 1);
|
|
|
|
//
|
|
buffer[ArraySize(buffer) - 1] = item;
|
|
}
|
|
void Add(
|
|
string item, // item want to add
|
|
string &buffer[] // Destination buffer
|
|
)
|
|
{
|
|
//
|
|
ArrayResize(
|
|
buffer,
|
|
ArraySize(buffer) + 1);
|
|
|
|
//
|
|
buffer[ArraySize(buffer) - 1] = item;
|
|
}
|
|
void Add(
|
|
double item, // item want to add
|
|
double &buffer[] // Destination buffer
|
|
)
|
|
{
|
|
//
|
|
ArrayResize(
|
|
buffer,
|
|
ArraySize(buffer) + 1);
|
|
|
|
//
|
|
buffer[ArraySize(buffer) - 1] = item;
|
|
}
|
|
void Add(
|
|
XOHCL &item, // item want to add
|
|
XOHCL &buffer[] // Destination buffer
|
|
)
|
|
{
|
|
//
|
|
ArrayResize(
|
|
buffer,
|
|
ArraySize(buffer) + 1);
|
|
|
|
//
|
|
buffer[ArraySize(buffer) - 1] = item;
|
|
}
|
|
void Add(
|
|
datetime &item, // item want to add
|
|
datetime &buffer[] // Destination buffer
|
|
)
|
|
{
|
|
//
|
|
ArrayResize(
|
|
buffer,
|
|
ArraySize(buffer) + 1);
|
|
|
|
//
|
|
buffer[ArraySize(buffer) - 1] = item;
|
|
}
|
|
|
|
//
|
|
// Add an Item to a Buffer if not Exists ...
|
|
void AddIfNotExists(
|
|
double value,
|
|
double &values[],
|
|
double smoothingPoint = 3)
|
|
{
|
|
//
|
|
double smoothingValue = smoothingPoint * GetPoints(_Symbol);
|
|
|
|
//
|
|
int valuesCount = ArraySize(values);
|
|
if (valuesCount <= 0)
|
|
{
|
|
//
|
|
Add(value,
|
|
values);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
bool isExists = false;
|
|
for (int i = 0; i < valuesCount; i++)
|
|
{
|
|
//
|
|
double iVal = values[i];
|
|
|
|
//
|
|
double diff = MathAbs(iVal - value);
|
|
|
|
//
|
|
if (iVal == value || diff < smoothingValue)
|
|
{
|
|
//
|
|
isExists = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (!isExists)
|
|
{
|
|
//
|
|
Add(value,
|
|
values);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add a Buffers Child to another Buffer
|
|
// if it's not Contains them ...
|
|
void AddsIfNotExists(
|
|
double &source[],
|
|
double &dest[],
|
|
double smoothingPoint = 3)
|
|
{
|
|
//
|
|
double smoothingValue = smoothingPoint * GetPoints(_Symbol);
|
|
|
|
//
|
|
int sourceCount = ArraySize(source);
|
|
if (sourceCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < sourceCount; i++)
|
|
{
|
|
//
|
|
double iSource = source[i];
|
|
|
|
//
|
|
AddIfNotExists(
|
|
iSource,
|
|
dest,
|
|
smoothingPoint);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Converts a Buffer to String Representation ...
|
|
string ToString(
|
|
const int &buffer[], // Specified Buffer
|
|
string separator = ",", // Specified Separator
|
|
bool addIndex = false, // Specified Add Items Indexes or Not
|
|
string indexLabel = "i:", // Specified Index Label
|
|
string indexSeparator = ">" // Specified Index Separator
|
|
|
|
)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
int bufferSize = ArraySize(buffer);
|
|
if (bufferSize <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < bufferSize; i++)
|
|
{
|
|
//
|
|
if (addIndex)
|
|
{
|
|
//
|
|
if (StringLen(indexLabel) > 0)
|
|
{
|
|
result += indexLabel + " ";
|
|
}
|
|
|
|
//
|
|
result += (string)i + " ";
|
|
|
|
//
|
|
if (StringLen(indexSeparator) > 0)
|
|
{
|
|
result += indexSeparator + " ";
|
|
}
|
|
}
|
|
|
|
//
|
|
string iItemString = (string)buffer[i];
|
|
|
|
//
|
|
result += iItemString;
|
|
|
|
//
|
|
if (i < bufferSize - 1)
|
|
{
|
|
result += separator;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
string ToString(
|
|
const double &buffer[], // Specified Buffer
|
|
string separator = ",", // Specified Separator
|
|
bool addIndex = false, // Specified Add Items Indexes or Not
|
|
string indexLabel = "i:", // Specified Index Label
|
|
string indexSeparator = ">" // Specified Index Separator
|
|
|
|
)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
int bufferSize = ArraySize(buffer);
|
|
if (bufferSize <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < bufferSize; i++)
|
|
{
|
|
//
|
|
if (addIndex)
|
|
{
|
|
//
|
|
if (StringLen(indexLabel) > 0)
|
|
{
|
|
result += indexLabel + " ";
|
|
}
|
|
|
|
//
|
|
result += (string)i + " ";
|
|
|
|
//
|
|
if (StringLen(indexSeparator) > 0)
|
|
{
|
|
result += indexSeparator + " ";
|
|
}
|
|
}
|
|
|
|
//
|
|
string iItemString = (string)buffer[i];
|
|
|
|
//
|
|
result += iItemString;
|
|
|
|
//
|
|
if (i < bufferSize - 1)
|
|
{
|
|
result += separator;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
string ToString(
|
|
const string &buffer[], // Specified Buffer
|
|
string separator = ",", // Specified Separator
|
|
bool addIndex = false, // Specified Add Items Indexes or Not
|
|
string indexLabel = "i:", // Specified Index Label
|
|
string indexSeparator = ">" // Specified Index Separator
|
|
|
|
)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
int bufferSize = ArraySize(buffer);
|
|
if (bufferSize <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < bufferSize; i++)
|
|
{
|
|
//
|
|
if (addIndex)
|
|
{
|
|
//
|
|
if (StringLen(indexLabel) > 0)
|
|
{
|
|
result += indexLabel + " ";
|
|
}
|
|
|
|
//
|
|
result += (string)i + " ";
|
|
|
|
//
|
|
if (StringLen(indexSeparator) > 0)
|
|
{
|
|
result += indexSeparator + " ";
|
|
}
|
|
}
|
|
|
|
//
|
|
string iItemString = (string)buffer[i];
|
|
|
|
//
|
|
result += iItemString;
|
|
|
|
//
|
|
if (i < bufferSize - 1)
|
|
{
|
|
result += separator;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
string ToString(
|
|
const datetime &buffer[], // Specified Buffer
|
|
string separator = ",", // Specified Separator
|
|
bool addIndex = false, // Specified Add Items Indexes or Not
|
|
string indexLabel = "i:", // Specified Index Label
|
|
string indexSeparator = ">" // Specified Index Separator
|
|
)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
int bufferSize = ArraySize(buffer);
|
|
if (bufferSize <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < bufferSize; i++)
|
|
{
|
|
//
|
|
if (addIndex)
|
|
{
|
|
//
|
|
if (StringLen(indexLabel) > 0)
|
|
{
|
|
result += indexLabel + " ";
|
|
}
|
|
|
|
//
|
|
result += (string)i + " ";
|
|
|
|
//
|
|
if (StringLen(indexSeparator) > 0)
|
|
{
|
|
result += indexSeparator + " ";
|
|
}
|
|
}
|
|
|
|
//
|
|
string iItemString = (string)buffer[i];
|
|
|
|
//
|
|
result += iItemString;
|
|
|
|
//
|
|
if (i < bufferSize - 1)
|
|
{
|
|
result += separator;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
template <typename T>
|
|
string ToString(T value)
|
|
{
|
|
return (string)value;
|
|
}
|
|
|
|
//
|
|
// Converts String to boolean ...
|
|
bool ToBoolean(string value)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (StringLen(value) <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
StringToLower(value);
|
|
result = value == "true";
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Search Array For Specific Item ...
|
|
template <typename T>
|
|
int FindIndex(
|
|
T item, // What is Search ...
|
|
T &buffer[] // Search in ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int count = ArraySize(buffer);
|
|
if (count <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
T iT = buffer[i];
|
|
|
|
//
|
|
if (iT == item)
|
|
{
|
|
//
|
|
result = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
template <typename T>
|
|
bool Contains(
|
|
T item, // What is Search ...
|
|
T &buffer[] // Search in ...
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int idx = FindIndex(
|
|
item,
|
|
buffer);
|
|
result = idx > -1;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
template <typename T>
|
|
bool Remove(
|
|
T item,
|
|
T &buffer[])
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int itemIndex = FindIndex(
|
|
item,
|
|
buffer);
|
|
if (itemIndex < 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArrayRemove(
|
|
buffer,
|
|
itemIndex,
|
|
1);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Split an String Representation of an Array ...
|
|
void SplitContent(
|
|
string &result[], // Hold Result ...
|
|
string content, // Source ...
|
|
string separator = ",", // Separator ...
|
|
bool forceCleanResult = true // Clean Result ...
|
|
)
|
|
{
|
|
//
|
|
if (forceCleanResult)
|
|
{
|
|
Clean(result);
|
|
}
|
|
|
|
//
|
|
if (separator == NULL || StringLen(separator) == 0)
|
|
{
|
|
separator = ",";
|
|
}
|
|
|
|
//
|
|
if (StringLen(content) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
StringSplit(
|
|
content,
|
|
StringGetCharacter(
|
|
separator,
|
|
0),
|
|
result);
|
|
}
|
|
|
|
//
|
|
// Extract Data from String ...
|
|
string ExtractString(
|
|
const string source, // Source String used for Extracting
|
|
const string startString, // Expression Start String must be Unique
|
|
const string endString // Where to End Extraction, usually a Sign
|
|
)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
// Validate String ...
|
|
if (
|
|
StringLen(source) == 0 ||
|
|
StringLen(endString) == 0 ||
|
|
StringLen(startString) == 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Start String Position ...
|
|
int sPos = StringFind(
|
|
source,
|
|
startString);
|
|
if (sPos < 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find End String Position after Start String ...
|
|
int searchEndFromPos = sPos + StringLen(startString);
|
|
int ePos = StringFind(
|
|
source,
|
|
endString,
|
|
searchEndFromPos);
|
|
if (ePos < 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Extract Data from Source ...
|
|
int dLength = ePos - searchEndFromPos;
|
|
result = StringSubstr(
|
|
source,
|
|
searchEndFromPos,
|
|
dLength);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Extract an Array of Contents ...
|
|
int ExtractStrings(
|
|
string &result[], // Hold Result
|
|
const string source, // Source String used for Extracting
|
|
const string startString, // Expression Start String must be Unique
|
|
const string endString // Where to End Extraction, usually a Sign
|
|
)
|
|
{
|
|
//
|
|
int mResult = 0;
|
|
|
|
//
|
|
Clean(result);
|
|
|
|
//
|
|
// Validate Args ...
|
|
int sourceLength = StringLen(source);
|
|
int startLength = StringLen(startString);
|
|
int endLength = StringLen(endString);
|
|
|
|
//
|
|
int minRequiredLength = startLength + endLength;
|
|
|
|
//
|
|
if (
|
|
endLength <= 0 ||
|
|
startLength <= 0 ||
|
|
sourceLength <= 0 ||
|
|
sourceLength < minRequiredLength)
|
|
{
|
|
return mResult;
|
|
}
|
|
|
|
//
|
|
// Make a Copy of Source for Manipulating ...
|
|
string workStr = source;
|
|
|
|
//
|
|
// Define a Loop ...
|
|
while (StringLen(workStr) > minRequiredLength)
|
|
{
|
|
//
|
|
// Find Item ...
|
|
string item = ExtractString(
|
|
workStr,
|
|
startString,
|
|
endString);
|
|
|
|
//
|
|
// Breakout when couldn't find anymore item ...
|
|
int itemLength = StringLen(item);
|
|
if (itemLength <= 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Prepare Item Source String for Replacing in Work String ...
|
|
string itemSource = startString + item + endString;
|
|
|
|
//
|
|
// Add Item to Result Array ...
|
|
Add(
|
|
item,
|
|
result);
|
|
|
|
//
|
|
// Replace Item Soure in Work String ...
|
|
StringReplace(
|
|
workStr,
|
|
itemSource,
|
|
"");
|
|
}
|
|
|
|
//
|
|
// Calculate Size of Array ...
|
|
mResult = ArraySize(result);
|
|
|
|
//
|
|
return mResult;
|
|
}
|
|
|
|
//
|
|
// Normalize a give Volume ...
|
|
double NormalizeVolume(
|
|
double volume, // desired volume to normalize
|
|
string symbol = NULL, // Specified Symbol for Normalization
|
|
int mLength = 2 // Length of Digits
|
|
)
|
|
{
|
|
//
|
|
double result = volume;
|
|
|
|
//
|
|
// Normalize Symbol ...
|
|
if (StringLen(symbol) == 0)
|
|
{
|
|
symbol = _Symbol;
|
|
}
|
|
|
|
//
|
|
// Normalize Digits ...
|
|
int digits = GetDigits(symbol);
|
|
mLength =
|
|
mLength == 0 || mLength > digits
|
|
? digits
|
|
: MathMin(mLength, digits);
|
|
|
|
//
|
|
// Normalize Volume ...
|
|
result = NormalizeDouble(result, mLength);
|
|
|
|
//
|
|
double maxAvailableVolume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
|
|
double minAvailableVolume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
|
|
|
|
//
|
|
// Validate Result ...
|
|
if (result > maxAvailableVolume)
|
|
{
|
|
result = maxAvailableVolume;
|
|
}
|
|
else if (result < minAvailableVolume)
|
|
{
|
|
result = minAvailableVolume;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Normallize Price ...
|
|
double NormalizePrice(
|
|
double price, // desired Price for normalization
|
|
string symbol = NULL // Specified Symbol for Normalization
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
// Mormalize Symbol ...
|
|
if (StringLen(symbol) == 0)
|
|
{
|
|
symbol = _Symbol;
|
|
}
|
|
|
|
//
|
|
double tickSize = 0;
|
|
result = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE, tickSize);
|
|
|
|
//
|
|
int digits = GetDigits(symbol);
|
|
result = NormalizeDouble(MathRound(price / tickSize) * tickSize, digits);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Expert Running in Testing Mode or not ...
|
|
bool IsRunningOnTestMode()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// check programm mode ...
|
|
result = MQL5InfoInteger(MQL5_TESTING);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Volume Weighted Moving Average ...
|
|
double iVWMA(
|
|
double price,
|
|
double volume,
|
|
int period,
|
|
int i,
|
|
int bars,
|
|
int instance = 0 //
|
|
)
|
|
{
|
|
#define ¤ instance
|
|
#ifdef _averageInstances
|
|
#define _functionInstances _averageInstances
|
|
#else #define _functionInstances 1
|
|
#endif
|
|
struct sVwmaArrayStruct
|
|
{
|
|
double price;
|
|
double volume;
|
|
double sump;
|
|
double sumv;
|
|
};
|
|
static sVwmaArrayStruct m_array[][_functionInstances];
|
|
static int m_arraySize = 0;
|
|
if (m_arraySize < bars)
|
|
{
|
|
int _res = ArrayResize(m_array, bars + 500);
|
|
if (_res <= bars)
|
|
return (0);
|
|
m_arraySize = _res;
|
|
}
|
|
|
|
//
|
|
//---
|
|
//
|
|
|
|
if (volume == 0)
|
|
volume = 1;
|
|
m_array[i][¤].price = volume * price;
|
|
m_array[i][¤].volume = volume;
|
|
if (i > period)
|
|
{
|
|
m_array[i][¤].sump = m_array[i - 1][¤].sump + m_array[i][¤].price - m_array[i - period][¤].price;
|
|
m_array[i][¤].sumv = m_array[i - 1][¤].sumv + volume - m_array[i - period][¤].volume;
|
|
}
|
|
else
|
|
{
|
|
m_array[i][¤].sump = m_array[i][¤].price;
|
|
m_array[i][¤].sumv = m_array[i][¤].volume;
|
|
for (int k = 1; k < period && i >= k; k++)
|
|
{
|
|
m_array[i][¤].sump += m_array[i - k][¤].price;
|
|
m_array[i][¤].sumv += m_array[i - k][¤].volume;
|
|
}
|
|
}
|
|
return (m_array[i][¤].sump / m_array[i][¤].sumv);
|
|
|
|
//
|
|
//---
|
|
//
|
|
|
|
#undef ¤ #undef _functionInstances
|
|
}
|
|
|
|
//
|
|
// Date Time Manipulation Functions ...
|
|
//
|
|
|
|
//
|
|
// Representation of Time Struct ...
|
|
// struct MqlDateTime
|
|
// {
|
|
// int year; // Year
|
|
// int mon; // Month
|
|
// int day; // Day
|
|
// int hour; // Hour
|
|
// int min; // Minutes
|
|
// int sec; // Seconds
|
|
// int day_of_week; // Day of week (0-Sunday, 1-Monday, ... ,6-Saturday)
|
|
// int day_of_year; // Day number of the year (January 1st is assigned the number value of zero)
|
|
// };
|
|
|
|
//
|
|
// Converts Time to Seconds ...
|
|
ulong TimeToSeconds(
|
|
datetime time // Specify time to Convert ...
|
|
)
|
|
{
|
|
//
|
|
ulong result = (ulong)time;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
ulong TimeToSeconds(
|
|
MqlDateTime &time // Specify time to Convert ...
|
|
)
|
|
{
|
|
//
|
|
datetime dTime = StructToTime(time);
|
|
|
|
//
|
|
ulong result = TimeToSeconds(dTime);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts Seconds To Time ...
|
|
datetime SecondsToTime(
|
|
ulong seconds // Specify Seconds to Convert ...
|
|
)
|
|
{
|
|
//
|
|
datetime result = (datetime)seconds;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
MqlDateTime SecondsToStruct(
|
|
ulong seconds // Specify Seconds to Convert ...
|
|
)
|
|
{
|
|
//
|
|
datetime dTime = SecondsToTime(seconds);
|
|
|
|
//
|
|
MqlDateTime result = {};
|
|
TimeToStruct(
|
|
dTime,
|
|
result);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts Time to MilliSeconds ...
|
|
ulong TimeToMilliSeconds(
|
|
datetime time // Specify time to Convert ...
|
|
)
|
|
{
|
|
//
|
|
ulong result = TimeToSeconds(time) * 1000;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
ulong TimeToMilliSeconds(
|
|
MqlDateTime &time // Specify time to Convert ...
|
|
)
|
|
{
|
|
//
|
|
datetime dTime = StructToTime(time);
|
|
|
|
//
|
|
ulong result = TimeToMilliSeconds(dTime);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts MillisSeconds to Time ...
|
|
datetime MilliSecondsToTiem(
|
|
ulong milliSeconds // Specify MilliSeconds to Convert ...
|
|
)
|
|
{
|
|
//
|
|
ulong seconds = milliSeconds / 1000;
|
|
|
|
//
|
|
datetime result = SecondsToTime(seconds);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
MqlDateTime MilliSecondsToStruct(
|
|
ulong milliSeconds // Specify MilliSeconds to Convert ...
|
|
)
|
|
{
|
|
//
|
|
datetime dTime = MilliSecondsToTiem(milliSeconds);
|
|
|
|
//
|
|
MqlDateTime result = {};
|
|
TimeToStruct(
|
|
dTime,
|
|
result);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve DateTime Structure ...
|
|
MqlDateTime GetCurrentTime()
|
|
{
|
|
//
|
|
MqlDateTime result = {};
|
|
|
|
//
|
|
TimeCurrent(result);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Current Time as Seconds ...
|
|
ulong GetCurrentTimeAsSeconds()
|
|
{
|
|
//
|
|
datetime time = TimeCurrent();
|
|
|
|
//
|
|
ulong result = TimeToSeconds(time);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Current Time as MilliSeconds ...
|
|
ulong GetCurrentTimeAsMilliSeconds()
|
|
{
|
|
//
|
|
datetime time = TimeCurrent();
|
|
|
|
//
|
|
ulong result = TimeToMilliSeconds(time);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Specified Candle Time ...
|
|
datetime GetCandleTime(
|
|
string symbol = "", // Specify Symbol
|
|
ENUM_TIMEFRAMES period = NULL, // Specify TimeFrame
|
|
int bar_index = 0 // Specify Bar Index
|
|
)
|
|
{
|
|
//
|
|
// Validate and Normalize Args ...
|
|
|
|
//
|
|
// Normalize Symbol ...
|
|
symbol = StringLen(symbol) == 0
|
|
? _Symbol
|
|
: symbol;
|
|
|
|
//
|
|
// Normalize Period ...
|
|
period = period == NULL
|
|
? _Period
|
|
: period;
|
|
|
|
//
|
|
// Retrieve Bar Time ...
|
|
datetime result = iTime(
|
|
symbol,
|
|
period,
|
|
bar_index);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Specified Candle Time ...
|
|
ulong GetCandleTimeAsSeconds(
|
|
string symbol = "", // Specify Symbol
|
|
ENUM_TIMEFRAMES period = NULL, // Specify TimeFrame
|
|
int bar_index = 0 // Specify Bar Index
|
|
)
|
|
{
|
|
//
|
|
// Retrieve Bar Time ...
|
|
datetime time = GetCandleTime(
|
|
symbol,
|
|
period,
|
|
bar_index);
|
|
|
|
//
|
|
ulong result = TimeToSeconds(time);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Specified Candle Time ...
|
|
ulong GetCandleTimeAsMilliSeconds(
|
|
string symbol = "", // Specify Symbol
|
|
ENUM_TIMEFRAMES period = NULL, // Specify TimeFrame
|
|
int bar_index = 0 // Specify Bar Index
|
|
)
|
|
{
|
|
//
|
|
// Retrieve Bar Time ...
|
|
datetime time = GetCandleTime(
|
|
symbol,
|
|
period,
|
|
bar_index);
|
|
|
|
//
|
|
ulong result = TimeToMilliSeconds(time);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve a Candle Time Structure ...
|
|
MqlDateTime GetCandleTimeStruct(
|
|
string symbol = "", // Specify Symbol
|
|
ENUM_TIMEFRAMES period = NULL, // Specify TimeFrame
|
|
int bar_index = 0 // Specify Bar Index
|
|
)
|
|
{
|
|
//
|
|
MqlDateTime result = {};
|
|
|
|
//
|
|
// Retrieve Bar Time ...
|
|
datetime barTime = GetCandleTime(
|
|
symbol,
|
|
period,
|
|
bar_index);
|
|
|
|
//
|
|
// Convert to Structure ...
|
|
TimeToStruct(barTime, result);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Number of Candles in a Day ...
|
|
int GetDailyCandleCount(ENUM_TIMEFRAMES mPeriod)
|
|
{
|
|
//
|
|
int seconds = PeriodSeconds(mPeriod);
|
|
|
|
//
|
|
int daySeconds = 24 * 60 * 60;
|
|
|
|
//
|
|
int result = daySeconds / seconds;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
int GetDailyCandleCount()
|
|
{
|
|
//
|
|
int result = GetDailyCandleCount(_Period);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
//
|
|
// Holds Month ...
|
|
static int xMonth = -1;
|
|
|
|
//
|
|
// Holds Day Of Week ...
|
|
static int xDayOfWeek = -1;
|
|
static int xForWeekDay = -1;
|
|
|
|
//
|
|
// Holds Day ...
|
|
static int xDay = -1;
|
|
|
|
//
|
|
// Holds Hour ...
|
|
static int xHour = -1;
|
|
|
|
//
|
|
// Reset Timing Variables ...
|
|
void ResetTiming()
|
|
{
|
|
//
|
|
xHour = -1;
|
|
xDay = -1;
|
|
xDayOfWeek = -1;
|
|
xMonth = -1;
|
|
}
|
|
|
|
//
|
|
// Detecting New Houre ...
|
|
bool IsNewHour()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Retrieve Current Time as Struct ...
|
|
MqlDateTime timeStruct = GetCurrentTime();
|
|
|
|
//
|
|
// Check Houre ...
|
|
result = timeStruct.hour != xHour;
|
|
if (result)
|
|
{
|
|
xHour = timeStruct.hour;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Detecting New Day ...
|
|
bool IsNewDay()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Retrieve Current Time as Struct ...
|
|
MqlDateTime timeStruct = GetCurrentTime();
|
|
|
|
//
|
|
// Check Houre ...
|
|
result = timeStruct.day_of_year != xDay;
|
|
if (result)
|
|
{
|
|
xDay = timeStruct.day_of_year;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Detecting New Week ...
|
|
bool IsNewWeek()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Retrieve Current Time as Struct ...
|
|
MqlDateTime timeStruct = GetCurrentTime();
|
|
|
|
//
|
|
// Check Week ...
|
|
// Since Week Starts From Monday in Forex World ...
|
|
// we Calculate Start of Week by 1-Monday ...
|
|
result =
|
|
xDayOfWeek == -1 &&
|
|
xForWeekDay == -1
|
|
? true
|
|
: timeStruct.day_of_week == 1 &&
|
|
timeStruct.day_of_year > xForWeekDay;
|
|
|
|
//
|
|
xForWeekDay = timeStruct.day_of_year;
|
|
xDayOfWeek = timeStruct.day_of_week;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Detecting End Of Week ...
|
|
bool IsWeekEnd()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Retrieve Current Time as Struct ...
|
|
MqlDateTime timeStruct = GetCurrentTime();
|
|
|
|
//
|
|
// Check WeekEnd ...
|
|
// Since Week Starts From Monday in Forex World ...
|
|
// we Calculate End of Week by 5-Friday ...
|
|
result =
|
|
xDayOfWeek != -1 &&
|
|
timeStruct.day_of_week == 5 &&
|
|
timeStruct.hour == 23 &&
|
|
timeStruct.min == 59 &&
|
|
timeStruct.sec == 59;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Detecting New Month ...
|
|
bool IsNewMonth()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Retrieve Current Time as Struct ...
|
|
MqlDateTime timeStruct = GetCurrentTime();
|
|
|
|
//
|
|
// Check Houre ...
|
|
result = timeStruct.mon != xMonth;
|
|
if (result)
|
|
{
|
|
xMonth = timeStruct.mon;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Hindmost Time Frame ...
|
|
ENUM_TIMEFRAMES GetHindmostTimeFrame(
|
|
ENUM_TIMEFRAMES mPeriod // Specified Period
|
|
)
|
|
{
|
|
//
|
|
ENUM_TIMEFRAMES result = NULL;
|
|
|
|
//
|
|
// Normalize Period ...
|
|
if (
|
|
mPeriod < 0 ||
|
|
mPeriod == NULL)
|
|
{
|
|
mPeriod = _Period;
|
|
}
|
|
|
|
//
|
|
switch (mPeriod)
|
|
{
|
|
//
|
|
case PERIOD_M1:
|
|
case PERIOD_M2:
|
|
case PERIOD_M3:
|
|
case PERIOD_M4:
|
|
result = PERIOD_H4;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M5:
|
|
case PERIOD_M6:
|
|
case PERIOD_M10:
|
|
case PERIOD_M12:
|
|
result = PERIOD_H8;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M15:
|
|
case PERIOD_M20:
|
|
result = PERIOD_H12;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M30:
|
|
result = PERIOD_D1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H1:
|
|
case PERIOD_H2:
|
|
case PERIOD_H3:
|
|
result = PERIOD_W1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H4:
|
|
case PERIOD_H6:
|
|
case PERIOD_H8:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H12:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_D1:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_W1:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
|
|
//
|
|
default:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Farest Time Frame ...
|
|
ENUM_TIMEFRAMES GetFarestTimeFrame(
|
|
ENUM_TIMEFRAMES mPeriod // Specified Period
|
|
)
|
|
{
|
|
//
|
|
ENUM_TIMEFRAMES result = NULL;
|
|
|
|
//
|
|
// Normalize Period ...
|
|
if (
|
|
mPeriod < 0 ||
|
|
mPeriod == NULL)
|
|
{
|
|
mPeriod = _Period;
|
|
}
|
|
|
|
//
|
|
switch (mPeriod)
|
|
{
|
|
//
|
|
case PERIOD_M1:
|
|
case PERIOD_M2:
|
|
case PERIOD_M3:
|
|
case PERIOD_M4:
|
|
result = PERIOD_H1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M5:
|
|
case PERIOD_M6:
|
|
case PERIOD_M10:
|
|
case PERIOD_M12:
|
|
result = PERIOD_H2;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M15:
|
|
case PERIOD_M20:
|
|
result = PERIOD_H3;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M30:
|
|
result = PERIOD_H4;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H1:
|
|
case PERIOD_H2:
|
|
case PERIOD_H3:
|
|
result = PERIOD_H8;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H4:
|
|
case PERIOD_H6:
|
|
case PERIOD_H8:
|
|
result = PERIOD_D1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H12:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_D1:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_W1:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
|
|
//
|
|
default:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Medium Time Frame ...
|
|
ENUM_TIMEFRAMES GetMediestTimeFrame(
|
|
ENUM_TIMEFRAMES mPeriod // Specified Period
|
|
)
|
|
{
|
|
//
|
|
ENUM_TIMEFRAMES result = NULL;
|
|
|
|
//
|
|
// Normalize Period ...
|
|
if (
|
|
mPeriod < 0 ||
|
|
mPeriod == NULL)
|
|
{
|
|
mPeriod = _Period;
|
|
}
|
|
|
|
//
|
|
switch (mPeriod)
|
|
{
|
|
//
|
|
case PERIOD_M1:
|
|
case PERIOD_M2:
|
|
case PERIOD_M3:
|
|
case PERIOD_M4:
|
|
result = PERIOD_M12;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M5:
|
|
case PERIOD_M6:
|
|
case PERIOD_M10:
|
|
case PERIOD_M12:
|
|
result = PERIOD_M30;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M15:
|
|
case PERIOD_M20:
|
|
result = PERIOD_H1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M30:
|
|
result = PERIOD_H2;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H1:
|
|
case PERIOD_H2:
|
|
case PERIOD_H3:
|
|
result = PERIOD_H6;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H4:
|
|
case PERIOD_H6:
|
|
case PERIOD_H8:
|
|
result = PERIOD_H12;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H12:
|
|
result = PERIOD_W1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_D1:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_W1:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
|
|
//
|
|
default:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Nearest Time Frame ...
|
|
ENUM_TIMEFRAMES GetNearestTimeFrame(
|
|
ENUM_TIMEFRAMES mPeriod // Specified Period
|
|
)
|
|
{
|
|
//
|
|
ENUM_TIMEFRAMES result = NULL;
|
|
|
|
//
|
|
// Normalize Period ...
|
|
if (
|
|
mPeriod < 0 ||
|
|
mPeriod == NULL)
|
|
{
|
|
mPeriod = _Period;
|
|
}
|
|
|
|
//
|
|
switch (mPeriod)
|
|
{
|
|
//
|
|
case PERIOD_M1:
|
|
case PERIOD_M2:
|
|
case PERIOD_M3:
|
|
case PERIOD_M4:
|
|
result = PERIOD_M5;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M5:
|
|
case PERIOD_M6:
|
|
case PERIOD_M10:
|
|
case PERIOD_M12:
|
|
result = PERIOD_M15;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M15:
|
|
case PERIOD_M20:
|
|
result = PERIOD_M30;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_M30:
|
|
result = PERIOD_H1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H1:
|
|
case PERIOD_H2:
|
|
case PERIOD_H3:
|
|
result = PERIOD_H4;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H4:
|
|
case PERIOD_H6:
|
|
case PERIOD_H8:
|
|
result = PERIOD_H12;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_H12:
|
|
result = PERIOD_D1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_D1:
|
|
result = PERIOD_W1;
|
|
break;
|
|
|
|
//
|
|
case PERIOD_W1:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
|
|
//
|
|
default:
|
|
result = PERIOD_MN1;
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Specific Time Frame Start Candle Time ...
|
|
datetime GetPeriodStartTime(
|
|
string mSymbol = NULL, // Specified Symbol ...
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Specified Period ...
|
|
datetime mTime = NULL // Specified Bar Time ...
|
|
)
|
|
{
|
|
//
|
|
// Normalize Arg ...
|
|
|
|
//
|
|
if (
|
|
mSymbol == NULL ||
|
|
StringLen(mSymbol) == 0)
|
|
{
|
|
mSymbol = _Symbol;
|
|
}
|
|
|
|
//
|
|
if (
|
|
mPeriod < 0 ||
|
|
mPeriod == NULL)
|
|
{
|
|
mPeriod = _Period;
|
|
}
|
|
|
|
//
|
|
if (
|
|
mTime < 0 ||
|
|
mTime == NULL)
|
|
{
|
|
mTime = TimeCurrent();
|
|
}
|
|
|
|
//
|
|
int barIndex = iBarShift(
|
|
mSymbol,
|
|
mPeriod,
|
|
mTime,
|
|
false);
|
|
|
|
//
|
|
datetime result = iTime(
|
|
mSymbol,
|
|
mPeriod,
|
|
barIndex);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
struct XCandleRemains
|
|
{
|
|
//
|
|
int days;
|
|
int hours;
|
|
int minutes;
|
|
int seconds;
|
|
};
|
|
|
|
//
|
|
string ToString(
|
|
XCandleRemains &item,
|
|
string dayId = "d",
|
|
string hourId = "h",
|
|
string minuteId = "m",
|
|
string secondId = "s",
|
|
string idSeparator = ": ",
|
|
string separator = ", ",
|
|
bool ignoreZeroValues = true)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
// Days ...
|
|
if (!ignoreZeroValues || item.days > 0)
|
|
{
|
|
result += dayId + idSeparator + (string)item.days + separator;
|
|
}
|
|
|
|
//
|
|
// Hours ...
|
|
if (!ignoreZeroValues || item.hours > 0)
|
|
{
|
|
//
|
|
string strHour = ToString(item.hours);
|
|
if (StringLen(strHour) == 1)
|
|
{
|
|
strHour = "0" + strHour;
|
|
}
|
|
|
|
//
|
|
result += hourId + idSeparator + strHour + separator;
|
|
}
|
|
|
|
//
|
|
// Minutes ...
|
|
if (!ignoreZeroValues || item.minutes > 0)
|
|
{
|
|
//
|
|
string strMinute = ToString(item.minutes);
|
|
if (StringLen(strMinute) == 1)
|
|
{
|
|
strMinute = "0" + strMinute;
|
|
}
|
|
|
|
//
|
|
result += minuteId + idSeparator + strMinute + separator;
|
|
}
|
|
|
|
//
|
|
// Seconds ...
|
|
if (!ignoreZeroValues || item.seconds > 0)
|
|
{
|
|
//
|
|
string strSec = ToString(item.seconds);
|
|
if (StringLen(strSec) == 1)
|
|
{
|
|
strSec = "0" + strSec;
|
|
}
|
|
|
|
//
|
|
result += secondId + idSeparator + strSec;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Specific Candles Ramained Time ...
|
|
void GetCandleRemainsTime(
|
|
XCandleRemains &result, // Holds Result ...
|
|
string mSymbol = NULL, // Specified Symbol ...
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Specified Period ...
|
|
int mBarIndex = 0 // Specified Bar Index ...
|
|
)
|
|
{
|
|
//
|
|
int minuteSecoonds = 60;
|
|
int hourSeconds = minuteSecoonds * 60;
|
|
int daySeconds = 24 * hourSeconds;
|
|
|
|
//
|
|
int periodSeconds = PeriodSeconds(
|
|
mPeriod);
|
|
datetime startTime = GetCandleTime(
|
|
mSymbol,
|
|
mPeriod,
|
|
mBarIndex);
|
|
|
|
//
|
|
int secondsDiff = (int)startTime + periodSeconds - (int)TimeCurrent();
|
|
|
|
//
|
|
int days = 0;
|
|
int hours = 0;
|
|
int minutes = 0;
|
|
int seconds = 0;
|
|
|
|
//
|
|
int mWorkingSecondsDiff = secondsDiff;
|
|
if (mWorkingSecondsDiff > daySeconds)
|
|
{
|
|
//
|
|
days = mWorkingSecondsDiff / daySeconds;
|
|
mWorkingSecondsDiff -= days * daySeconds;
|
|
}
|
|
if (mWorkingSecondsDiff > hourSeconds)
|
|
{
|
|
//
|
|
hours = mWorkingSecondsDiff / hourSeconds;
|
|
mWorkingSecondsDiff -= hours * hourSeconds;
|
|
}
|
|
if (mWorkingSecondsDiff > minuteSecoonds)
|
|
{
|
|
//
|
|
minutes = mWorkingSecondsDiff / minuteSecoonds;
|
|
mWorkingSecondsDiff -= minutes * minuteSecoonds;
|
|
}
|
|
seconds = mWorkingSecondsDiff;
|
|
|
|
//
|
|
result.days = days;
|
|
result.hours = hours;
|
|
result.minutes = minutes;
|
|
result.seconds = seconds;
|
|
}
|
|
|
|
//
|
|
// Converts an String to TimeFrame ...
|
|
ENUM_TIMEFRAMES ToPeriod(string value)
|
|
{
|
|
//
|
|
if (StringLen(value) == 0)
|
|
{
|
|
return _Period;
|
|
}
|
|
|
|
//
|
|
StringTrimLeft(value);
|
|
StringTrimRight(value);
|
|
|
|
//
|
|
ENUM_TIMEFRAMES result = _Period;
|
|
|
|
//
|
|
if (value == "M1")
|
|
{
|
|
result = PERIOD_M1;
|
|
}
|
|
else if (value == "M2")
|
|
{
|
|
result = PERIOD_M2;
|
|
}
|
|
else if (value == "M3")
|
|
{
|
|
result = PERIOD_M3;
|
|
}
|
|
else if (value == "M4")
|
|
{
|
|
result = PERIOD_M4;
|
|
}
|
|
else if (value == "M5")
|
|
{
|
|
result = PERIOD_M5;
|
|
}
|
|
else if (value == "M6")
|
|
{
|
|
result = PERIOD_M6;
|
|
}
|
|
else if (value == "M10")
|
|
{
|
|
result = PERIOD_M10;
|
|
}
|
|
else if (value == "M12")
|
|
{
|
|
result = PERIOD_M12;
|
|
}
|
|
else if (value == "M15")
|
|
{
|
|
result = PERIOD_M15;
|
|
}
|
|
else if (value == "M20")
|
|
{
|
|
result = PERIOD_M20;
|
|
}
|
|
else if (value == "M30")
|
|
{
|
|
result = PERIOD_M30;
|
|
}
|
|
else if (value == "H1")
|
|
{
|
|
result = PERIOD_H1;
|
|
}
|
|
else if (value == "H2")
|
|
{
|
|
result = PERIOD_H2;
|
|
}
|
|
else if (value == "H3")
|
|
{
|
|
result = PERIOD_H3;
|
|
}
|
|
else if (value == "H4")
|
|
{
|
|
result = PERIOD_H4;
|
|
}
|
|
else if (value == "H6")
|
|
{
|
|
result = PERIOD_H6;
|
|
}
|
|
else if (value == "H8")
|
|
{
|
|
result = PERIOD_H8;
|
|
}
|
|
else if (value == "H12")
|
|
{
|
|
result = PERIOD_H12;
|
|
}
|
|
else if (value == "D1")
|
|
{
|
|
result = PERIOD_D1;
|
|
}
|
|
else if (value == "W1")
|
|
{
|
|
result = PERIOD_W1;
|
|
}
|
|
else if (value == "MN1")
|
|
{
|
|
result = PERIOD_MN1;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts Period to String ...
|
|
string ToString(ENUM_TIMEFRAMES period)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
string mPStr = EnumToString(period);
|
|
|
|
string mPStrParts[];
|
|
int partsCount = StringSplit(
|
|
mPStr,
|
|
StringGetCharacter("_", 0),
|
|
mPStrParts);
|
|
if (partsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = mPStrParts[1];
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// TYPES ...
|
|
//
|
|
|
|
//
|
|
// Retrieve Specific Object Types Name ...
|
|
template <typename T>
|
|
string GetTypeName(const T &t)
|
|
{
|
|
return typename(T);
|
|
}
|
|
|
|
//
|
|
// TAGGING ...
|
|
template <typename T>
|
|
string GenerateTag(
|
|
T &model
|
|
) {
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
string tag = model.ToString();
|
|
if (StringLen(tag) == 0) {
|
|
return result;
|
|
}
|
|
|
|
//
|
|
static XSCMD5 md5;
|
|
|
|
//
|
|
result = md5.Hash(tag);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// SIGNAL ...
|
|
|
|
//
|
|
// Do All Normalization on Specific Signal ...
|
|
void NormalizeSignal(XSignal &signal)
|
|
{
|
|
//
|
|
// ENTRY ...
|
|
if (signal.entry > 0)
|
|
{
|
|
signal.entry = NormalizePrice(signal.entry, signal.symbol);
|
|
}
|
|
|
|
//
|
|
// TP ...
|
|
if (signal.tp > 0)
|
|
{
|
|
signal.tp = NormalizePrice(signal.tp, signal.symbol);
|
|
}
|
|
|
|
//
|
|
// SL ...
|
|
if (signal.sl > 0)
|
|
{
|
|
signal.sl = NormalizePrice(signal.sl, signal.symbol);
|
|
}
|
|
|
|
//
|
|
// VOLUME ...
|
|
if (signal.volume > 0)
|
|
{
|
|
signal.volume = NormalizeVolume(signal.volume, signal.symbol);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Prepare Base Signal ...
|
|
XSignal CreateSignal(
|
|
string symbol, // Trading Symbol ...
|
|
ENUM_TIMEFRAMES period, // Trading Time Frame ...
|
|
ENUM_POSITION_TYPE type, // Position Type ...
|
|
ENUM_X_ORDER_MODES mode, // Order Execution Mode ...ّ
|
|
double entry, // Signal Entry Execution ...
|
|
double volume, // Volume ...
|
|
double tp = 0, // TP ...
|
|
double sl = 0 // SL ...
|
|
)
|
|
{
|
|
//
|
|
XSignal result;
|
|
Clean(result);
|
|
|
|
//
|
|
result.tp = tp;
|
|
result.sl = sl;
|
|
result.mode = mode;
|
|
result.entry = entry;
|
|
result.period = period;
|
|
result.symbol = symbol;
|
|
result.volume = volume;
|
|
|
|
//
|
|
NormalizeSignal(result);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Changes ...
|
|
bool HandleValueChanged(
|
|
XValueChanged &holder[], // Change Holder Buffer ...
|
|
const double &state[], // Data State Buffer ...
|
|
const double &source[], // Data Source Buffer ...
|
|
datetime time = 0, // Checking Time ...
|
|
int resizeHolder = 100 // Resize Holder if had More than it ...
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (time <= 0)
|
|
{
|
|
time = TimeCurrent();
|
|
}
|
|
|
|
//
|
|
if (ArraySize(source) <= 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double from = source[1];
|
|
double to = source[0];
|
|
|
|
//
|
|
result =
|
|
to != from && to != EMPTY_VALUE &&
|
|
state[0] != state[1] && state[0] != EMPTY_VALUE;
|
|
if (result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XValueChanged lastChange;
|
|
bool hasLastChange =
|
|
GetLastItem(
|
|
lastChange,
|
|
holder);
|
|
result =
|
|
!hasLastChange
|
|
? true
|
|
: lastChange.at < time &&
|
|
lastChange.to != to &&
|
|
lastChange.from != from;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Handle Resizing ...
|
|
if (resizeHolder > 0)
|
|
{
|
|
//
|
|
int holderCount = ArraySize(holder);
|
|
if (holderCount >= resizeHolder)
|
|
{
|
|
//
|
|
Clean(holder);
|
|
|
|
//
|
|
Add(
|
|
lastChange,
|
|
holder);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create a Model for add ...
|
|
lastChange.to = to;
|
|
lastChange.at = time;
|
|
lastChange.from = from;
|
|
|
|
//
|
|
Add(
|
|
lastChange,
|
|
holder);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// END Provided Functions ...
|
|
//
|