refactor(oi): improve data extraction and consolidate documentation
- Fix MQL5 API usage in EA to use correct CopyRates and POSITION_TYPE enums - Refactor scraper data extraction to use drop_duplicates for unique strikes - Consolidate Windows setup guide into main README - Add virtual environment batch files for easier setup and execution - Simplify run_scraper.bat to focus on core execution - Normalize lot calculation to use SymbolInfo.LotsStep()
This commit is contained in:
@@ -358,64 +358,66 @@ void OnNewM1Bar(datetime newBarTime) {
|
||||
}
|
||||
|
||||
void CalculateVolumeEMAFromHistory() {
|
||||
double volumeArray[];
|
||||
ArraySetAsSeries(volumeArray, true);
|
||||
CopyVolume(_Symbol, PERIOD_M1, 1, InpVolumeEmaPeriod + 1, volumeArray);
|
||||
|
||||
double emaAlpha = 2.0 / (InpVolumeEmaPeriod + 1);
|
||||
double sum = 0;
|
||||
|
||||
for(int i = 0; i < InpVolumeEmaPeriod; i++) {
|
||||
sum += volumeArray[i];
|
||||
}
|
||||
double avgVolume = sum / InpVolumeEmaPeriod;
|
||||
|
||||
if(VolumeEmaValue == 0) {
|
||||
VolumeEmaValue = avgVolume;
|
||||
} else {
|
||||
VolumeEmaValue = emaAlpha * avgVolume + (1 - emaAlpha) * VolumeEmaValue;
|
||||
}
|
||||
MqlRates rates[];
|
||||
ArraySetAsSeries(rates, true);
|
||||
int copied = CopyRates(_Symbol, PERIOD_M1, 1, InpVolumeEmaPeriod + 1, rates);
|
||||
if(copied < InpVolumeEmaPeriod + 1) return;
|
||||
|
||||
double emaAlpha = 2.0 / (InpVolumeEmaPeriod + 1);
|
||||
double sum = 0;
|
||||
|
||||
for(int i = 0; i < InpVolumeEmaPeriod; i++) {
|
||||
sum += (double)rates[i].tick_volume;
|
||||
}
|
||||
double avgVolume = sum / InpVolumeEmaPeriod;
|
||||
|
||||
if(VolumeEmaValue == 0) {
|
||||
VolumeEmaValue = avgVolume;
|
||||
} else {
|
||||
VolumeEmaValue = emaAlpha * avgVolume + (1 - emaAlpha) * VolumeEmaValue;
|
||||
}
|
||||
}
|
||||
|
||||
void DetectAbsorptionFromHistory() {
|
||||
double volumeArray[];
|
||||
ArraySetAsSeries(volumeArray, true);
|
||||
CopyVolume(_Symbol, PERIOD_M1, 1, InpAbsorptionBars + 1, volumeArray);
|
||||
|
||||
double avgVolume = 0;
|
||||
for(int i = 0; i < InpAbsorptionBars; i++) {
|
||||
avgVolume += volumeArray[i];
|
||||
}
|
||||
avgVolume /= InpAbsorptionBars;
|
||||
|
||||
double volumeThreshold = avgVolume * InpMinVolumeMultiplier;
|
||||
|
||||
int sellAbsorptionCount = 0;
|
||||
int buyAbsorptionCount = 0;
|
||||
|
||||
for(int i = 1; i <= InpAbsorptionBars; i++) {
|
||||
double high = iHigh(_Symbol, PERIOD_M1, i);
|
||||
double low = iLow(_Symbol, PERIOD_M1, i);
|
||||
double close = iClose(_Symbol, PERIOD_M1, i);
|
||||
double open = iOpen(_Symbol, PERIOD_M1, i);
|
||||
int barVolume = (int)iVolume(_Symbol, PERIOD_M1, i);
|
||||
|
||||
double barRange = high - low;
|
||||
double barDrift = close - open;
|
||||
|
||||
bool highVolume = barVolume > volumeThreshold;
|
||||
bool lowDrift = barRange < InpMaxPriceDriftPoints * _Point;
|
||||
|
||||
if(highVolume && lowDrift && barDrift < 0) {
|
||||
sellAbsorptionCount++;
|
||||
}
|
||||
|
||||
if(highVolume && lowDrift && barDrift > 0) {
|
||||
buyAbsorptionCount++;
|
||||
}
|
||||
}
|
||||
|
||||
int requiredBars = MathCeil(InpAbsorptionBars / 2.0);
|
||||
MqlRates rates[];
|
||||
ArraySetAsSeries(rates, true);
|
||||
int copied = CopyRates(_Symbol, PERIOD_M1, 1, InpAbsorptionBars + 1, rates);
|
||||
if(copied < InpAbsorptionBars + 1) return;
|
||||
|
||||
double avgVolume = 0;
|
||||
for(int i = 0; i < InpAbsorptionBars; i++) {
|
||||
avgVolume += (double)rates[i].tick_volume;
|
||||
}
|
||||
avgVolume /= InpAbsorptionBars;
|
||||
|
||||
double volumeThreshold = avgVolume * InpMinVolumeMultiplier;
|
||||
|
||||
int sellAbsorptionCount = 0;
|
||||
int buyAbsorptionCount = 0;
|
||||
|
||||
for(int i = 1; i <= InpAbsorptionBars; i++) {
|
||||
double high = rates[i].high;
|
||||
double low = rates[i].low;
|
||||
double close = rates[i].close;
|
||||
double open = rates[i].open;
|
||||
int barVolume = (int)rates[i].tick_volume;
|
||||
|
||||
double barRange = high - low;
|
||||
double barDrift = close - open;
|
||||
|
||||
bool highVolume = barVolume > volumeThreshold;
|
||||
bool lowDrift = barRange < InpMaxPriceDriftPoints * _Point;
|
||||
|
||||
if(highVolume && lowDrift && barDrift < 0) {
|
||||
sellAbsorptionCount++;
|
||||
}
|
||||
|
||||
if(highVolume && lowDrift && barDrift > 0) {
|
||||
buyAbsorptionCount++;
|
||||
}
|
||||
}
|
||||
|
||||
int requiredBars = (int)MathCeil(InpAbsorptionBars / 2.0);
|
||||
|
||||
if(sellAbsorptionCount >= requiredBars && IsPriceNearPutStrike()) {
|
||||
CurrentAbsorptionState = ABSORPTION_SELL;
|
||||
@@ -679,8 +681,8 @@ bool IsAtSupport() {
|
||||
}
|
||||
|
||||
void ExecuteBuyTrade() {
|
||||
double lotSize = CalculateLotSize(ORDER_TYPE_BUY);
|
||||
if(lotSize <= 0) return;
|
||||
double lotSize = CalculateLotSize(POSITION_TYPE_BUY);
|
||||
if(lotSize <= 0) return;
|
||||
|
||||
double sl = 0, tp = 0;
|
||||
double nearestPutStrike = GetNearestPutStrike();
|
||||
@@ -715,8 +717,8 @@ void ExecuteBuyTrade() {
|
||||
}
|
||||
|
||||
void ExecuteSellTrade() {
|
||||
double lotSize = CalculateLotSize(ORDER_TYPE_SELL);
|
||||
if(lotSize <= 0) return;
|
||||
double lotSize = CalculateLotSize(POSITION_TYPE_SELL);
|
||||
if(lotSize <= 0) return;
|
||||
|
||||
double sl = 0, tp = 0;
|
||||
double nearestCallStrike = GetNearestCallStrike();
|
||||
@@ -820,8 +822,8 @@ double CalculateLotSize(ENUM_POSITION_TYPE tradeType) {
|
||||
}
|
||||
|
||||
double NormalizeLot(double lot) {
|
||||
double step = SymbolInfo.LotStep();
|
||||
return MathFloor(lot / step) * step;
|
||||
double step = SymbolInfo.LotsStep();
|
||||
return MathFloor(lot / step) * step;
|
||||
}
|
||||
|
||||
void ManagePositions() {
|
||||
@@ -1037,8 +1039,11 @@ void CreateDashboard() {
|
||||
}
|
||||
|
||||
void UpdateDashboard() {
|
||||
UpdateLabel("DB_Symbol", 20, 45, "Symbol: " + _Symbol, clrWhite, 8);
|
||||
UpdateLabel("DB_Price", 20, 65, "Price: " + DoubleToString(SpotPrice, 2), clrCyan, 8);
|
||||
MqlRates rates[];
|
||||
int copied = CopyRates(_Symbol, PERIOD_M1, 0, 1, rates);
|
||||
|
||||
UpdateLabel("DB_Symbol", 20, 45, "Symbol: " + _Symbol, clrWhite, 8);
|
||||
UpdateLabel("DB_Price", 20, 65, "Price: " + DoubleToString(SpotPrice, 2), clrCyan, 8);
|
||||
|
||||
string deltaText = DoubleToString(OrderFlowDeltaPercent, 1) + "%";
|
||||
color deltaColor = OrderFlowDeltaPercent > 0 ? clrLime : (OrderFlowDeltaPercent < 0 ? clrRed : clrGray);
|
||||
@@ -1063,9 +1068,9 @@ void UpdateDashboard() {
|
||||
|
||||
UpdateLabel("DB_Absorption", 20, 105, "Absorption: " + absorptionText, absorptionColor, 8);
|
||||
|
||||
int currentVol = CurrentBarVolume > 0 ? CurrentBarVolume : (int)Volume(0);
|
||||
UpdateLabel("DB_Volume", 20, 125, "Volume: " + IntegerToString(currentVol) +
|
||||
" (Avg: " + IntegerToString((int)VolumeEmaValue) + ")", clrWhite, 8);
|
||||
int currentVol = CurrentBarVolume > 0 ? CurrentBarVolume : (copied > 0 ? (int)rates[0].tick_volume : 0);
|
||||
UpdateLabel("DB_Volume", 20, 125, "Volume: " + IntegerToString(currentVol) +
|
||||
" (Avg: " + IntegerToString((int)VolumeEmaValue) + ")", clrWhite, 8);
|
||||
|
||||
string driftText = DoubleToString(PriceDrift / _Point, 1) + " pts";
|
||||
color driftColor = PriceDrift < InpMaxPriceDriftPoints * _Point ? clrLime : clrOrange;
|
||||
|
||||
Reference in New Issue
Block a user