349 行
9.6 KiB
MQL5
349 行
9.6 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| BinaryEncoder.mqh |
|
|
//| Price-to-Binary Encoding Functions |
|
|
//| For Quantum-Compatible Market Analysis |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "ForexTrader Quantum EA"
|
|
#property link "https://github.com/simonokwundue-ops/Experienced-FX-Trader"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Binary Price Encoder Class |
|
|
//+------------------------------------------------------------------+
|
|
class CBinaryEncoder
|
|
{
|
|
public:
|
|
//--- Encode price movements to binary string
|
|
static string EncodePriceMovements(const double &prices[], int count)
|
|
{
|
|
if(count < 2) return "";
|
|
|
|
string binary = "";
|
|
|
|
for(int i = 1; i < count; i++)
|
|
{
|
|
// 1 if price increased, 0 if decreased or equal
|
|
binary += (prices[i] > prices[i-1]) ? "1" : "0";
|
|
}
|
|
|
|
return binary;
|
|
}
|
|
|
|
//--- Encode MqlRates array to binary
|
|
static string EncodeRates(const MqlRates &rates[], int count = -1)
|
|
{
|
|
int size = (count > 0) ? count : ArraySize(rates);
|
|
if(size < 2) return "";
|
|
|
|
string binary = "";
|
|
|
|
// Process from oldest to newest
|
|
for(int i = size - 2; i >= 0; i--)
|
|
{
|
|
binary += (rates[i].close > rates[i+1].close) ? "1" : "0";
|
|
}
|
|
|
|
return binary;
|
|
}
|
|
|
|
//--- Encode with volatility weighting
|
|
static string EncodeWithVolatility(const MqlRates &rates[], int count = -1)
|
|
{
|
|
int size = (count > 0) ? count : ArraySize(rates);
|
|
if(size < 2) return "";
|
|
|
|
string binary = "";
|
|
double avgRange = CalculateAverageRange(rates, size);
|
|
|
|
for(int i = size - 2; i >= 0; i--)
|
|
{
|
|
double priceChange = rates[i].close - rates[i+1].close;
|
|
double candleRange = rates[i].high - rates[i].low;
|
|
|
|
// Weight by volatility significance
|
|
if(MathAbs(priceChange) > avgRange * 0.3)
|
|
{
|
|
// Significant move
|
|
binary += (priceChange > 0) ? "1" : "0";
|
|
}
|
|
else
|
|
{
|
|
// Small move - consider as continuation
|
|
if(i < size - 2)
|
|
binary += binary[StringLen(binary) - 1]; // Copy previous
|
|
else
|
|
binary += "0";
|
|
}
|
|
}
|
|
|
|
return binary;
|
|
}
|
|
|
|
//--- Decode binary string to probability
|
|
static double DecodeToProbability(const string binary)
|
|
{
|
|
int length = StringLen(binary);
|
|
if(length == 0) return 0.5;
|
|
|
|
int ones = 0;
|
|
for(int i = 0; i < length; i++)
|
|
{
|
|
if(StringGetCharacter(binary, i) == '1')
|
|
ones++;
|
|
}
|
|
|
|
return (double)ones / length;
|
|
}
|
|
|
|
//--- Calculate pattern frequency
|
|
static double CalculatePatternFrequency(const string binary, const string pattern)
|
|
{
|
|
int binaryLen = StringLen(binary);
|
|
int patternLen = StringLen(pattern);
|
|
|
|
if(patternLen == 0 || patternLen > binaryLen)
|
|
return 0;
|
|
|
|
int matches = 0;
|
|
int possibleMatches = binaryLen - patternLen + 1;
|
|
|
|
for(int i = 0; i < possibleMatches; i++)
|
|
{
|
|
string segment = StringSubstr(binary, i, patternLen);
|
|
if(segment == pattern)
|
|
matches++;
|
|
}
|
|
|
|
return (double)matches / possibleMatches;
|
|
}
|
|
|
|
//--- Extract recent pattern
|
|
static string ExtractRecentPattern(const string binary, int length)
|
|
{
|
|
int binaryLen = StringLen(binary);
|
|
if(length > binaryLen) length = binaryLen;
|
|
|
|
return StringSubstr(binary, 0, length);
|
|
}
|
|
|
|
//--- Calculate pattern entropy
|
|
static double CalculatePatternEntropy(const string binary)
|
|
{
|
|
int length = StringLen(binary);
|
|
if(length < 2) return 0;
|
|
|
|
// Count consecutive patterns
|
|
int changes = 0;
|
|
for(int i = 1; i < length; i++)
|
|
{
|
|
if(StringGetCharacter(binary, i) != StringGetCharacter(binary, i-1))
|
|
changes++;
|
|
}
|
|
|
|
// Entropy measure: more changes = higher entropy
|
|
return (double)changes / (length - 1);
|
|
}
|
|
|
|
//--- Detect trend in binary sequence
|
|
static int DetectTrend(const string binary, int lookback = 20)
|
|
{
|
|
int length = StringLen(binary);
|
|
if(length == 0) return 0;
|
|
|
|
if(lookback > length) lookback = length;
|
|
|
|
string recent = StringSubstr(binary, 0, lookback);
|
|
int ones = 0;
|
|
|
|
for(int i = 0; i < lookback; i++)
|
|
{
|
|
if(StringGetCharacter(recent, i) == '1')
|
|
ones++;
|
|
}
|
|
|
|
double ratio = (double)ones / lookback;
|
|
|
|
if(ratio > 0.60) return 1; // Uptrend
|
|
else if(ratio < 0.40) return -1; // Downtrend
|
|
else return 0; // No clear trend
|
|
}
|
|
|
|
//--- Calculate momentum score
|
|
static double CalculateMomentumScore(const string binary, int period = 10)
|
|
{
|
|
int length = StringLen(binary);
|
|
if(length < period) period = length;
|
|
if(period == 0) return 0;
|
|
|
|
string recent = StringSubstr(binary, 0, period);
|
|
int ones = 0;
|
|
|
|
for(int i = 0; i < period; i++)
|
|
{
|
|
if(StringGetCharacter(recent, i) == '1')
|
|
ones++;
|
|
}
|
|
|
|
// Score from -1 (strong down) to +1 (strong up)
|
|
return (2.0 * ones / period) - 1.0;
|
|
}
|
|
|
|
//--- Find similar patterns in history
|
|
static double FindHistoricalSimilarity(const string currentPattern,
|
|
const string historical,
|
|
int patternLength)
|
|
{
|
|
if(patternLength > StringLen(currentPattern))
|
|
patternLength = StringLen(currentPattern);
|
|
|
|
string pattern = StringSubstr(currentPattern, 0, patternLength);
|
|
int histLength = StringLen(historical);
|
|
|
|
if(patternLength > histLength)
|
|
return 0;
|
|
|
|
double maxSimilarity = 0;
|
|
|
|
// Scan historical data for similar patterns
|
|
for(int i = 0; i <= histLength - patternLength; i++)
|
|
{
|
|
string segment = StringSubstr(historical, i, patternLength);
|
|
double similarity = CalculateSimilarity(pattern, segment);
|
|
|
|
if(similarity > maxSimilarity)
|
|
maxSimilarity = similarity;
|
|
}
|
|
|
|
return maxSimilarity;
|
|
}
|
|
|
|
//--- Calculate similarity between two binary strings
|
|
static double CalculateSimilarity(const string binary1, const string binary2)
|
|
{
|
|
int len1 = StringLen(binary1);
|
|
int len2 = StringLen(binary2);
|
|
|
|
if(len1 != len2) return 0;
|
|
if(len1 == 0) return 0;
|
|
|
|
int matches = 0;
|
|
|
|
for(int i = 0; i < len1; i++)
|
|
{
|
|
if(StringGetCharacter(binary1, i) == StringGetCharacter(binary2, i))
|
|
matches++;
|
|
}
|
|
|
|
return (double)matches / len1;
|
|
}
|
|
|
|
//--- Pad binary string to specified length
|
|
static string PadBinary(const string binary, int targetLength, bool padLeft = true)
|
|
{
|
|
int currentLength = StringLen(binary);
|
|
|
|
if(currentLength >= targetLength)
|
|
return binary;
|
|
|
|
string padding = "";
|
|
for(int i = 0; i < targetLength - currentLength; i++)
|
|
{
|
|
padding += "0";
|
|
}
|
|
|
|
return padLeft ? (padding + binary) : (binary + padding);
|
|
}
|
|
|
|
//--- Convert binary string to integer
|
|
static long BinaryToInteger(const string binary)
|
|
{
|
|
int length = StringLen(binary);
|
|
if(length == 0 || length > 63) return 0; // Prevent overflow
|
|
|
|
long result = 0;
|
|
long power = 1;
|
|
|
|
for(int i = length - 1; i >= 0; i--)
|
|
{
|
|
if(StringGetCharacter(binary, i) == '1')
|
|
result += power;
|
|
power *= 2;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//--- Convert integer to binary string
|
|
static string IntegerToBinary(long value, int minLength = 8)
|
|
{
|
|
if(value < 0) value = 0;
|
|
|
|
string binary = "";
|
|
|
|
if(value == 0)
|
|
{
|
|
binary = "0";
|
|
}
|
|
else
|
|
{
|
|
while(value > 0)
|
|
{
|
|
binary = ((value % 2 == 1) ? "1" : "0") + binary;
|
|
value /= 2;
|
|
}
|
|
}
|
|
|
|
// Pad to minimum length
|
|
return PadBinary(binary, minLength, true);
|
|
}
|
|
|
|
//--- Helper: Calculate average range
|
|
static double CalculateAverageRange(const MqlRates &rates[], int count)
|
|
{
|
|
if(count < 1) return 0;
|
|
|
|
double totalRange = 0;
|
|
|
|
for(int i = 0; i < count; i++)
|
|
{
|
|
totalRange += (rates[i].high - rates[i].low);
|
|
}
|
|
|
|
return totalRange / count;
|
|
}
|
|
|
|
//--- Compress binary using run-length encoding (for storage/comparison)
|
|
static string CompressBinary(const string binary)
|
|
{
|
|
int length = StringLen(binary);
|
|
if(length == 0) return "";
|
|
|
|
string compressed = "";
|
|
ushort currentChar = StringGetCharacter(binary, 0);
|
|
int count = 1;
|
|
|
|
for(int i = 1; i < length; i++)
|
|
{
|
|
ushort nextChar = StringGetCharacter(binary, i);
|
|
|
|
if(nextChar == currentChar)
|
|
{
|
|
count++;
|
|
}
|
|
else
|
|
{
|
|
compressed += IntegerToString(count) + ShortToString(currentChar);
|
|
currentChar = nextChar;
|
|
count = 1;
|
|
}
|
|
}
|
|
|
|
// Add final run
|
|
compressed += IntegerToString(count) + ShortToString(currentChar);
|
|
|
|
return compressed;
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|