1414 lines
25 KiB
Plaintext
1414 lines
25 KiB
Plaintext
|
|
//
|
|
// Calculate TP/SL for Specified Type of Positions ...
|
|
void CalculateTPSL(
|
|
double &mSL, // Hold SL
|
|
double &mTP, // Hold TP
|
|
ENUM_POSITION_TYPE mType, // Position Type Long (Buy) / Short (Sell)
|
|
double mEntry, // Entry Price
|
|
double mR2R = 1, // Provided Risk To Reward Ratio
|
|
double slPrice = 0, // Provided SL Price
|
|
double tpPrice = 0, // Provided TP Price
|
|
double priceToRisk = 0, // If Entry equal to Provided SL Price Risk Point
|
|
double priceToReward = 0 // If Entry equal to Provided TP Price Reward Point
|
|
)
|
|
{
|
|
//
|
|
// if Both TP and SL Provided, ignore R2R and Calculate direct ...
|
|
// if SL provided, Calculate TP based on Provided R2R ...
|
|
// if TP provided, Calculate SL based on Provided R2R ...
|
|
// default R2R is set to 1 ...
|
|
|
|
//
|
|
mSL = 0;
|
|
mTP = 0;
|
|
|
|
//
|
|
bool isLong = IsLong(mType);
|
|
|
|
//
|
|
// Set Default R2R ...
|
|
if (mR2R < 1)
|
|
{
|
|
mR2R = 1;
|
|
}
|
|
|
|
//
|
|
if (mEntry <= 0 ||
|
|
(tpPrice <= 0 && slPrice <= 0))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
double risk = 0;
|
|
double reward = 0;
|
|
|
|
//
|
|
bool canCalculateBasedOnSL = slPrice > 0 &&
|
|
(isLong
|
|
? slPrice <= mEntry
|
|
: slPrice >= mEntry);
|
|
|
|
//
|
|
bool canCalculateBasedOnTP = tpPrice > 0 &&
|
|
(isLong
|
|
? tpPrice >= mEntry
|
|
: tpPrice <= mEntry);
|
|
|
|
//
|
|
if (canCalculateBasedOnSL && !canCalculateBasedOnTP)
|
|
{
|
|
//
|
|
risk = MathAbs(mEntry - slPrice);
|
|
if (risk == 0)
|
|
{
|
|
risk = priceToRisk;
|
|
}
|
|
reward = risk * mR2R;
|
|
}
|
|
else if (!canCalculateBasedOnSL && canCalculateBasedOnTP)
|
|
{
|
|
//
|
|
reward = MathAbs(mEntry - tpPrice);
|
|
if (reward == 0)
|
|
{
|
|
reward = priceToReward;
|
|
}
|
|
risk = reward / mR2R;
|
|
}
|
|
else if (!canCalculateBasedOnSL && !canCalculateBasedOnTP)
|
|
{
|
|
//
|
|
bool canSetTPPrice = isLong
|
|
? tpPrice > mEntry
|
|
: tpPrice < mEntry;
|
|
if (canSetTPPrice)
|
|
{
|
|
mTP = tpPrice;
|
|
}
|
|
|
|
//
|
|
bool canSetSLPrice = isLong
|
|
? slPrice < mEntry
|
|
: slPrice > mEntry;
|
|
if (canSetSLPrice)
|
|
{
|
|
mSL = slPrice;
|
|
}
|
|
|
|
//
|
|
return;
|
|
}
|
|
else if (canCalculateBasedOnSL && canCalculateBasedOnTP)
|
|
{
|
|
//
|
|
bool canSetTPPrice = isLong
|
|
? tpPrice > mEntry
|
|
: tpPrice < mEntry;
|
|
if (canSetTPPrice)
|
|
{
|
|
mTP = tpPrice;
|
|
}
|
|
|
|
//
|
|
bool canSetSLPrice = isLong
|
|
? slPrice < mEntry
|
|
: slPrice > mEntry;
|
|
if (canSetSLPrice)
|
|
{
|
|
mSL = slPrice;
|
|
}
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
mTP = isLong
|
|
? mEntry + reward
|
|
: mEntry - reward;
|
|
|
|
//
|
|
mSL = isLong
|
|
? mEntry - risk
|
|
: mEntry + risk;
|
|
}
|
|
|
|
//
|
|
bool CalculateTPSLByPoint(
|
|
double &mSL, // Hold SL
|
|
double &mTP, // Hold TP
|
|
ENUM_POSITION_TYPE mType, // Position Type Long (Buy) / Short (Sell)
|
|
double mEntry, // Entry Price
|
|
double mPointValue, // Point Value
|
|
double mR2R = 1, // Provided Risk To Reward Ratio
|
|
double slPoint = 0, // Provided SL Point
|
|
double tpPoint = 0 // Provided TP Point
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
mSL = 0;
|
|
mTP = 0;
|
|
|
|
//
|
|
bool isLong = IsLong(mType);
|
|
|
|
//
|
|
// Set Default R2R ...
|
|
if (mR2R < 1)
|
|
{
|
|
mR2R = 1;
|
|
}
|
|
|
|
//
|
|
if (mEntry <= 0 ||
|
|
mPointValue <= 0 ||
|
|
(slPoint <= 0 && tpPoint <= 0))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double risk = 0;
|
|
double reward = 0;
|
|
|
|
//
|
|
bool canCalculateBasedOnSL = slPoint > 0;
|
|
|
|
//
|
|
bool canCalculateBasedOnTP = tpPoint > 0;
|
|
|
|
//
|
|
if (!canCalculateBasedOnSL && !canCalculateBasedOnTP)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (canCalculateBasedOnSL && canCalculateBasedOnTP)
|
|
{
|
|
//
|
|
reward = tpPoint * mPointValue;
|
|
risk = slPoint * mPointValue;
|
|
}
|
|
else if (!canCalculateBasedOnSL && canCalculateBasedOnTP)
|
|
{
|
|
//
|
|
reward = tpPoint * mPointValue;
|
|
risk = reward / mR2R;
|
|
}
|
|
else if (canCalculateBasedOnSL && !canCalculateBasedOnTP)
|
|
{
|
|
//
|
|
risk = slPoint * mPointValue;
|
|
reward = risk * mR2R;
|
|
}
|
|
|
|
//
|
|
result = risk > 0 && reward > 0;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
mTP = isLong
|
|
? mEntry + reward
|
|
: mEntry - reward;
|
|
|
|
//
|
|
mSL = isLong
|
|
? mEntry - risk
|
|
: mEntry + risk;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool CalculateTPSLByPrice(
|
|
double &mSL, // Hold SL
|
|
double &mTP, // Hold TP
|
|
ENUM_POSITION_TYPE mType, // Position Type Long (Buy) / Short (Sell)
|
|
double mEntry, // Entry Price
|
|
double mR2R = 1 // Provided Risk To Reward Ratio
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bool isLong = IsLong(mType);
|
|
|
|
//
|
|
// Set Default R2R ...
|
|
if (mR2R < 1)
|
|
{
|
|
mR2R = 1;
|
|
}
|
|
|
|
//
|
|
if (mEntry <= 0 ||
|
|
(mSL <= 0 && mTP <= 0))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double risk = 0;
|
|
double reward = 0;
|
|
|
|
//
|
|
bool canCalculateBasedOnSL = mSL > 0;
|
|
bool canCalculateBasedOnTP = mTP > 0;
|
|
|
|
//
|
|
if (
|
|
!canCalculateBasedOnSL &&
|
|
!canCalculateBasedOnTP)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (!canCalculateBasedOnSL && canCalculateBasedOnTP)
|
|
{
|
|
//
|
|
reward = MathAbs(mTP - mEntry);
|
|
risk = reward / mR2R;
|
|
}
|
|
else if (canCalculateBasedOnSL && !canCalculateBasedOnTP)
|
|
{
|
|
//
|
|
risk = MathAbs(mEntry - mSL);
|
|
reward = risk * mR2R;
|
|
}
|
|
|
|
//
|
|
result = risk > 0 && reward > 0;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
mTP = isLong
|
|
? mEntry + reward
|
|
: mEntry - reward;
|
|
|
|
//
|
|
mSL = isLong
|
|
? mEntry - risk
|
|
: mEntry + risk;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Calculate Momentum Changes based on Given Price
|
|
*/
|
|
double CalculateMomentum(
|
|
double currentPrice,
|
|
double previousPrice //
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Detect Possible Momentum Changes
|
|
* Using MqlTick ...
|
|
*/
|
|
bool DetectMomentumChange(
|
|
ENUM_POSITION_TYPE type,
|
|
string mSymbol = NULL,
|
|
int mLength = 14 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
|
|
//
|
|
MqlTick ticks[];
|
|
int copied = CopyTicks(
|
|
mSymbol,
|
|
ticks,
|
|
COPY_TICKS_ALL,
|
|
0,
|
|
mLength + 1 //
|
|
);
|
|
|
|
//
|
|
result = copied > mLength;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double previousPrice = GetTickExit(
|
|
ticks[mLength],
|
|
type,
|
|
mSymbol //
|
|
);
|
|
for (int i = mLength - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
double currentPrice = GetTickExit(
|
|
ticks[i],
|
|
type,
|
|
mSymbol //
|
|
);
|
|
|
|
//
|
|
double momentum = CalculateMomentum(
|
|
currentPrice,
|
|
previousPrice //
|
|
);
|
|
|
|
//
|
|
if (fabs(momentum) > 1.0)
|
|
{
|
|
//
|
|
result = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
//
|
|
// Extension Methods ...
|
|
|
|
//
|
|
// Find Swing Points ...
|
|
int FindSwing(
|
|
string mSymbol, // Trading Symbol ...
|
|
ENUM_TIMEFRAMES mPeriod, // Trading Period ...
|
|
ENUM_X_SWING_TYPE mMode, // Swing Based On Price mode ...
|
|
int mLength, // Loopback ...
|
|
int bar_index // BarIndex ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (StringLen(mSymbol) == 0 || (mMode != X_SWING_HIGH && mMode != X_SWING_LOW))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int current = bar_index;
|
|
int founded = FindNextSwing(
|
|
mSymbol,
|
|
mPeriod,
|
|
mMode,
|
|
(mLength * 2) + 1,
|
|
current - mLength);
|
|
|
|
//
|
|
while (founded != current)
|
|
{
|
|
//
|
|
current = FindNextSwing(
|
|
mSymbol,
|
|
mPeriod,
|
|
mMode,
|
|
mLength,
|
|
current + 1);
|
|
|
|
//
|
|
founded = FindNextSwing(
|
|
mSymbol,
|
|
mPeriod,
|
|
mMode,
|
|
(mLength * 2) + 1,
|
|
current - mLength);
|
|
}
|
|
|
|
//
|
|
result = current;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Next Swing ...
|
|
int FindNextSwing(
|
|
string mSymbol, // Trading Symbol ...
|
|
ENUM_TIMEFRAMES mPeriod, // Trading Period ...
|
|
ENUM_X_SWING_TYPE mMode, // 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;
|
|
}
|
|
|
|
//
|
|
ENUM_SERIESMODE mSeriesMode = ToSeriesMode(mMode);
|
|
|
|
//
|
|
result = mMode == X_SWING_HIGH
|
|
? iHighest(
|
|
mSymbol,
|
|
mPeriod,
|
|
mSeriesMode,
|
|
mLength,
|
|
bar_index)
|
|
: iLowest(
|
|
mSymbol,
|
|
mPeriod,
|
|
mSeriesMode,
|
|
mLength,
|
|
bar_index);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Extract values of swings from specified Collection ...
|
|
*
|
|
* @param swings: XSwingPoint instance Collection ...
|
|
* @param values: double Collection ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int ExtractSwings(
|
|
XSwingPoint &swings[],
|
|
double &values[] //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(values);
|
|
|
|
//
|
|
int count = ArraySize(swings);
|
|
if (!IsValidSize(count))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
Add(
|
|
swings[i].swing,
|
|
values //
|
|
);
|
|
}
|
|
|
|
//
|
|
result = ArraySize(values);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Functions ...
|
|
|
|
//
|
|
// Validators ...
|
|
|
|
//
|
|
// Validate an String has length and not NULL ...
|
|
|
|
//
|
|
// Validate a Date ...
|
|
|
|
//
|
|
// Validate a Period Param ...
|
|
|
|
|
|
//
|
|
// Validate Specific Period Mode ...
|
|
|
|
|
|
//
|
|
// As IS ...
|
|
|
|
//
|
|
// Normalizers ...
|
|
|
|
|
|
//
|
|
// Prices ...
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Calculates Price Change Percentage based on
|
|
* Several Params ...
|
|
*
|
|
* @param _symbol: Symbol ...
|
|
* @param _period: Time Frame ...
|
|
* @param _from: start Bar Index ...
|
|
* @param _length: Length of Bars ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double GetPriceChanged(
|
|
string _symbol = NULL,
|
|
ENUM_TIMEFRAMES _period = NULL,
|
|
int _from = 0,
|
|
int _length = 3 //
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
NormalizeSymbol(_symbol);
|
|
NormalizePeriod(_period);
|
|
|
|
//
|
|
if (_from < 0)
|
|
{
|
|
_from = 0;
|
|
}
|
|
|
|
//
|
|
if (_length < 2)
|
|
{
|
|
_length = 2;
|
|
}
|
|
|
|
//
|
|
double closes[];
|
|
int copiedCloses = CopyClose(
|
|
_symbol,
|
|
_period,
|
|
_from,
|
|
_length,
|
|
closes //
|
|
);
|
|
if (copiedCloses < _length)
|
|
{
|
|
return result;
|
|
}
|
|
ArrayReverse(closes);
|
|
|
|
//
|
|
double change = (closes[0] - closes[_length - 1]) / closes[_length - 1] * 100;
|
|
result = change;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieve Current Tick ...
|
|
*/
|
|
bool GetTick(
|
|
string mSymbol,
|
|
MqlTick &tick //
|
|
)
|
|
{
|
|
return SymbolInfoTick(mSymbol, tick);
|
|
}
|
|
|
|
/**
|
|
* Retrieve Tick Entry ...
|
|
*/
|
|
double GetTickEntry(
|
|
MqlTick &mTick,
|
|
ENUM_POSITION_TYPE type,
|
|
string mSymbol = NULL //
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
|
|
//
|
|
result =
|
|
IsLong(type)
|
|
? mTick.ask
|
|
: mTick.bid;
|
|
result = NormalizePrice(result, mSymbol);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieve Tick Exit ...
|
|
*/
|
|
double GetTickExit(
|
|
MqlTick &mTick,
|
|
ENUM_POSITION_TYPE type,
|
|
string mSymbol = NULL //
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
mSymbol = NormalizeSymbol(mSymbol);
|
|
|
|
//
|
|
result =
|
|
IsLong(type)
|
|
? mTick.bid
|
|
: mTick.ask;
|
|
result = NormalizePrice(result, mSymbol);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Fill Specified Applied Prices ...
|
|
int FillPrice(
|
|
double &buffer[],
|
|
ENUM_APPLIED_PRICE _mAppliedTo = PRICE_CLOSE,
|
|
string _mSymbol = NULL,
|
|
ENUM_TIMEFRAMES _mPeriod = NULL,
|
|
int _mStart = 0,
|
|
int _mLoopback = 10 //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (_mStart < 0)
|
|
{
|
|
_mStart = 0;
|
|
}
|
|
|
|
//
|
|
if (_mLoopback < 1)
|
|
{
|
|
_mLoopback = 1;
|
|
}
|
|
|
|
//
|
|
_mSymbol = NormalizeSymbol(_mSymbol);
|
|
_mPeriod = NormalizePeriod(_mPeriod);
|
|
|
|
//
|
|
Clean(buffer);
|
|
ArraySetAsSeries(buffer, true);
|
|
|
|
//
|
|
double open[];
|
|
result = CopyOpen(
|
|
_mSymbol,
|
|
_mPeriod,
|
|
_mStart,
|
|
_mLoopback,
|
|
open //
|
|
);
|
|
if (!IsValidSize(result))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double high[];
|
|
result = CopyHigh(
|
|
_mSymbol,
|
|
_mPeriod,
|
|
_mStart,
|
|
_mLoopback,
|
|
high //
|
|
);
|
|
if (!IsValidSize(result))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double low[];
|
|
result = CopyLow(
|
|
_mSymbol,
|
|
_mPeriod,
|
|
_mStart,
|
|
_mLoopback,
|
|
low //
|
|
);
|
|
if (!IsValidSize(result))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double close[];
|
|
result = CopyClose(
|
|
_mSymbol,
|
|
_mPeriod,
|
|
_mStart,
|
|
_mLoopback,
|
|
close //
|
|
);
|
|
if (!IsValidSize(result))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < result; i++)
|
|
{
|
|
//
|
|
double iPrice = GetAppliedPrice(
|
|
_mAppliedTo,
|
|
open,
|
|
high,
|
|
low,
|
|
close,
|
|
i //
|
|
);
|
|
|
|
//
|
|
Add(
|
|
iPrice,
|
|
buffer //
|
|
);
|
|
}
|
|
|
|
//
|
|
result = ArraySize(buffer);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Symbols ...
|
|
|
|
|
|
//
|
|
// Time / Date ...
|
|
|
|
|
|
//
|
|
// Retrieve Day of Week ...
|
|
ENUM_X_WEEK_DAYS GetDayOfWeek(
|
|
datetime time = NULL //
|
|
)
|
|
{
|
|
//
|
|
ENUM_X_WEEK_DAYS result = X_WEEK_DAY_NONE;
|
|
|
|
//
|
|
time = NormalizeTime(time);
|
|
MqlDateTime timeStruct;
|
|
bool hasDate = TimeToStruct(
|
|
time,
|
|
timeStruct //
|
|
);
|
|
if (!hasDate)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = (ENUM_X_WEEK_DAYS)timeStruct.day_of_week;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// 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)
|
|
// };
|
|
|
|
|
|
//
|
|
// Bar Times ...
|
|
|
|
//
|
|
// Retrieve Specified Bar Time ...
|
|
ulong GetBarTimeAsSeconds(
|
|
string mSymbol = "", // Specify Symbol
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame
|
|
int barIndex = 0 // Specify Bar Index
|
|
)
|
|
{
|
|
//
|
|
// Retrieve Bar Time ...
|
|
datetime time = GetBarTime(
|
|
mSymbol,
|
|
mPeriod,
|
|
barIndex);
|
|
|
|
//
|
|
ulong result = TimeToSeconds(time);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Specified Bar Time ...
|
|
ulong GetBarTimeAsMilliSeconds(
|
|
string mSymbol = "", // Specify Symbol
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame
|
|
int barIndex = 0 // Specify Bar Index
|
|
)
|
|
{
|
|
//
|
|
// Retrieve Bar Time ...
|
|
datetime time = GetBarTime(
|
|
mSymbol,
|
|
mPeriod,
|
|
barIndex);
|
|
|
|
//
|
|
ulong result = TimeToMilliSeconds(time);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve a Bar Time Structure ...
|
|
MqlDateTime GetBarTimeStruct(
|
|
string mSymbol = "", // Specify Symbol
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame
|
|
int barIndex = 0 // Specify Bar Index
|
|
)
|
|
{
|
|
//
|
|
MqlDateTime result = {};
|
|
|
|
//
|
|
// Retrieve Bar Time ...
|
|
datetime barTime = GetBarTime(
|
|
mSymbol,
|
|
mPeriod,
|
|
barIndex);
|
|
|
|
//
|
|
// Convert to Structure ...
|
|
TimeToStruct(barTime, result);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Last Available Bar Time of
|
|
// Dest Period inside Source Period ...
|
|
datetime GetLastBarTime(
|
|
ENUM_TIMEFRAMES sourcePeriod,
|
|
ENUM_TIMEFRAMES destPeriod //
|
|
)
|
|
{
|
|
//
|
|
datetime result = NULL;
|
|
|
|
//
|
|
if (!IsValid(sourcePeriod) ||
|
|
!IsValid(destPeriod))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int sourceSeconds = PeriodSeconds(sourcePeriod);
|
|
int destSeconds = PeriodSeconds(destPeriod);
|
|
if (sourceSeconds < destSeconds)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL sourceBar;
|
|
bool isInited = sourceBar.Init(
|
|
_Symbol,
|
|
sourcePeriod,
|
|
0 //
|
|
);
|
|
if (!isInited)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = (datetime)((((int)sourceBar.time) + sourceSeconds) - destSeconds);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Other Tools ...
|
|
|
|
|
|
//
|
|
// Check Bar Reject Specified Value ...
|
|
bool IsBarReject(
|
|
double value,
|
|
ENUM_X_DIRECTION dir,
|
|
XOHCL &bar //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = value > 0 &&
|
|
bar.IsValid() &&
|
|
HasDirection(dir);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isUp = IsBullish(dir);
|
|
bool isDown = IsBearish(dir);
|
|
|
|
//
|
|
result =
|
|
//
|
|
isUp
|
|
? bar.IsBullish() &&
|
|
bar.low < value &&
|
|
bar.GetDown() > value
|
|
: isDown
|
|
? bar.IsBearish() &&
|
|
bar.high > value &&
|
|
bar.GetUp() < value
|
|
: false
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Bar Break Specified Value ...
|
|
bool IsBarBreak(
|
|
double value,
|
|
ENUM_X_DIRECTION dir,
|
|
XOHCL &bar //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = value > 0 &&
|
|
bar.IsValid() &&
|
|
HasDirection(dir);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL pBar;
|
|
result = bar.GetPreviousBar(pBar);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isUp = IsBullish(dir);
|
|
bool isDown = IsBearish(dir);
|
|
|
|
//
|
|
result =
|
|
isUp
|
|
? bar.IsBullish() &&
|
|
((bar.GetDown() < value &&
|
|
bar.GetUp() > value) ||
|
|
(bar.close > value &&
|
|
pBar.close < value))
|
|
: isDown
|
|
? bar.IsBearish() &&
|
|
((bar.GetUp() > value &&
|
|
bar.GetDown() < value) ||
|
|
(bar.close < value &&
|
|
pBar.close > value))
|
|
: false;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Fib Level ...
|
|
double GetFibonacciLevel(
|
|
double upPrice, // Upper Bound
|
|
double downPrice, // Downer Bound
|
|
double level, // Level Multiplier Factor
|
|
int direction // From Down to Up < 0, other wise Vice Versa
|
|
//
|
|
)
|
|
{
|
|
//
|
|
double ling = upPrice - downPrice;
|
|
double pLevel = (ling / 100) * (level * 100);
|
|
|
|
//
|
|
double result = direction > 0 ? upPrice - pLevel : downPrice + pLevel;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double GetFibonacciLevel(
|
|
double mUp,
|
|
double mDown,
|
|
ENUM_X_FIBO_LEVELS mLevel,
|
|
ENUM_X_DIRECTION mForDir //
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
double levelValue = GetFiboLevelValue(mLevel);
|
|
|
|
//
|
|
bool isValid =
|
|
//
|
|
mUp > 0 &&
|
|
mDown > 0 &&
|
|
levelValue > 0 &&
|
|
mUp > mDown &&
|
|
HasDirection(mForDir)
|
|
//
|
|
;
|
|
if (!isValid)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish(mForDir);
|
|
|
|
//
|
|
double ling = mUp - mDown;
|
|
double pLevel = (ling / 100) * (levelValue * 100);
|
|
|
|
//
|
|
result =
|
|
isBullish
|
|
? mUp - pLevel
|
|
: mDown + pLevel;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Method 1
|
|
// Normalize between 1 and 0 ...
|
|
template <typename T>
|
|
double GetNormalizedValueMethod1(
|
|
T &buffer[], // Array which required to Normalize
|
|
int mLength, // Length of Normalization
|
|
int mStart = 0, // start index
|
|
int digits = 5 // Normalization Digits
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (digits <= 5)
|
|
{
|
|
digits = 5;
|
|
}
|
|
|
|
//
|
|
int bufferSize = ArraySize(buffer);
|
|
if (!IsValidSize(bufferSize))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Normalize Count ...
|
|
NormalizeCount(
|
|
mStart,
|
|
mLength,
|
|
buffer //
|
|
);
|
|
|
|
//
|
|
T max = 0;
|
|
T min = 0;
|
|
|
|
//
|
|
if (bufferSize != mLength)
|
|
{
|
|
//
|
|
T tmp[];
|
|
Copy(
|
|
mStart,
|
|
mLength,
|
|
buffer,
|
|
tmp //
|
|
);
|
|
|
|
//
|
|
max = GetMax(tmp);
|
|
min = GetMin(tmp);
|
|
}
|
|
|
|
//
|
|
if (bufferSize == mLength)
|
|
{
|
|
//
|
|
max = GetMax(buffer);
|
|
min = GetMin(buffer);
|
|
}
|
|
|
|
//
|
|
T iValue = buffer[mStart];
|
|
|
|
//
|
|
double minMaxDiff = (max - min);
|
|
if (minMaxDiff <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = (iValue - min) / minMaxDiff;
|
|
|
|
//
|
|
result = NormalizeDouble(result, digits);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Method 2
|
|
// Normalize Between Specified Upper and Lower ...
|
|
template <typename T>
|
|
double GetNormalizedValueMethod2(
|
|
T &buffer[], // Array which required to Normalize
|
|
int mLength, // Length of Normalization
|
|
int mUpper, // Specified Upper Value
|
|
int mLower, // Specified Lower Value
|
|
int mStart = 0, // start index
|
|
int digits = 5 // Normalization Digits
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (digits <= 5)
|
|
{
|
|
digits = 5;
|
|
}
|
|
|
|
//
|
|
int bufferSize = ArraySize(buffer);
|
|
if (!IsValidSize(bufferSize))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Normalize Count ...
|
|
NormalizeCount(
|
|
mStart,
|
|
mLength,
|
|
buffer //
|
|
);
|
|
|
|
//
|
|
T max = 0;
|
|
T min = 0;
|
|
|
|
//
|
|
if (bufferSize != mLength)
|
|
{
|
|
//
|
|
T tmp[];
|
|
Copy(
|
|
mStart,
|
|
mLength,
|
|
buffer,
|
|
tmp //
|
|
);
|
|
|
|
//
|
|
max = GetMax(tmp);
|
|
min = GetMin(tmp);
|
|
}
|
|
|
|
//
|
|
if (bufferSize == mLength)
|
|
{
|
|
//
|
|
max = GetMax(buffer);
|
|
min = GetMin(buffer);
|
|
}
|
|
|
|
//
|
|
T iValue = buffer[mStart];
|
|
|
|
//
|
|
double minMaxDiff = (max - min);
|
|
double boundaryDiff = (mUpper - mLower);
|
|
if (minMaxDiff <= 0 || boundaryDiff <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = boundaryDiff / (minMaxDiff * (iValue - max) + max);
|
|
|
|
//
|
|
result = NormalizeDouble(result, digits);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
void NormalizeBuffer(
|
|
double &source[], // Source Buffer
|
|
double &dest[], // Result Buffer
|
|
double upper = 100, // Upper Value to Normalize
|
|
double lower = -100, // Lower Value to Normalize
|
|
int size = -1, // Size Of Normalization
|
|
int digits = 5 // Digits for Result
|
|
)
|
|
{
|
|
//
|
|
if (size <= 0)
|
|
{
|
|
size = ArraySize(source);
|
|
}
|
|
|
|
//
|
|
bool asSeriesFlag = ArrayGetAsSeries(source);
|
|
|
|
//
|
|
ArraySetAsSeries(source, false);
|
|
ArraySetAsSeries(dest, false);
|
|
|
|
//
|
|
double min = ArrayMinimum(source, 0, size);
|
|
double max = ArrayMaximum(source, 0, size);
|
|
|
|
//
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
//
|
|
double iNormal = lower + ((source[i] - min) / (max - min)) * (upper - lower);
|
|
|
|
//
|
|
if (digits > 0)
|
|
{
|
|
iNormal = NormalizeDouble(iNormal, digits);
|
|
}
|
|
|
|
//
|
|
dest[i] = iNormal;
|
|
}
|
|
|
|
//
|
|
ArraySetAsSeries(source, asSeriesFlag);
|
|
ArraySetAsSeries(dest, asSeriesFlag);
|
|
}
|
|
|
|
//
|
|
// Templates ...
|
|
|
|
//
|
|
// Bar XOHCL ...
|
|
|
|
//
|
|
// String ...
|
|
|
|
//
|
|
// Periods / Cycles ...
|
|
|
|
|
|
//
|
|
// Moving Average ...
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
|
// //
|
|
// double ranges[];
|
|
// int rangesCount = GetPriceRange(
|
|
// ranges,
|
|
// bar,
|
|
// forcBodyInRange,
|
|
// loopback //
|
|
// );
|
|
// result = IsValidSize(rangesCount);
|
|
// if (!result)
|
|
// {
|
|
// //
|
|
// Clean(ranges);
|
|
|
|
// //
|
|
// return result;
|
|
// }
|
|
|
|
//
|
|
// Calculate Ranges ...
|
|
// double rangeMax = GetMax(ranges);
|
|
// double rangeMin = GetMin(ranges);
|
|
// double rangeAverage = GetAverage(ranges);
|
|
|