423 lines
20 KiB
MQL5
423 lines
20 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| AdvancedPriceActionEA.mq5 |
|
|
//| Copyright 2025, Google Gemini |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2025, Google Gemini"
|
|
#property link "https://www.google.com"
|
|
#property version "1.00"
|
|
|
|
#include <Trade\Trade.mqh>
|
|
#include <NeuralNet.mqh>
|
|
|
|
input string InpModelFile = "AdvancedPriceActionNN.bin";
|
|
input double InpConfidence = 0.8;
|
|
input double InpLotSize = 0.1;
|
|
input int InpMagic = 1234567;
|
|
|
|
// --- Model Parameters (Loaded from File) ---
|
|
int gLookback;
|
|
int gAsianStart, gAsianEnd;
|
|
int gLondonStart, gLondonEnd;
|
|
int gNYStart, gNYEnd;
|
|
double gTargetTP_Mult, gTargetSL_Mult;
|
|
|
|
CTrade Trade;
|
|
CNeuralNet *Net;
|
|
int GlobalTopology[];
|
|
datetime lastBarTime = 0;
|
|
int handleEMA50, handleEMA200, handleATR_D1;
|
|
|
|
// --- Structures ---
|
|
struct SessionStats {
|
|
double H, L;
|
|
double Volume; // Total volume
|
|
double OR30_H, OR30_L;
|
|
double OR30_Vol;
|
|
bool valid;
|
|
};
|
|
|
|
struct DailyProfile {
|
|
double POC;
|
|
double VAH, VAL;
|
|
double Crests[];
|
|
double Troughs[];
|
|
bool valid;
|
|
};
|
|
|
|
struct SessionData {
|
|
SessionStats Asian;
|
|
SessionStats London;
|
|
SessionStats NY;
|
|
DailyProfile Profile;
|
|
};
|
|
|
|
// Maps DayIndex -> Data
|
|
SessionData DayMap[];
|
|
datetime baseTime;
|
|
|
|
// VWAP Arrays
|
|
struct VWAPPoint {
|
|
double vwap_d, std_d;
|
|
double vwap_w, std_w;
|
|
double vwap_m, std_m;
|
|
};
|
|
VWAPPoint VWAPBuffer[];
|
|
|
|
double AvgVol_Asian[2], AvgVol_London[2], AvgVol_NY[2];
|
|
|
|
// --- Helper Functions ---
|
|
int GetDayIndex(datetime t) { return (int)((t - baseTime) / 86400); }
|
|
double MathMean(double &arr[]) { if(ArraySize(arr)==0) return 1; double s=0; for(int i=0; i<ArraySize(arr); i++) s+=arr[i]; return s/ArraySize(arr); }
|
|
|
|
// Forward Decl
|
|
bool LoadModelWithHeader(string filename);
|
|
void PrecomputeData(const MqlRates &rates[], int total);
|
|
|
|
// --- Standard Events ---
|
|
|
|
int OnInit()
|
|
{
|
|
Trade.SetExpertMagicNumber(InpMagic);
|
|
handleEMA50 = iMA(_Symbol, PERIOD_H1, 50, 0, MODE_EMA, PRICE_CLOSE);
|
|
handleEMA200 = iMA(_Symbol, PERIOD_H1, 200, 0, MODE_EMA, PRICE_CLOSE);
|
|
handleATR_D1 = iATR(_Symbol, PERIOD_D1, 14);
|
|
if(handleEMA50 == INVALID_HANDLE || handleEMA200 == INVALID_HANDLE || handleATR_D1 == INVALID_HANDLE) return(INIT_FAILED);
|
|
|
|
if(!LoadModelWithHeader(InpModelFile)) {
|
|
Print("Fatal Error: Could not load model and metadata.");
|
|
return(INIT_FAILED);
|
|
}
|
|
|
|
Print("Model Loaded Successfully.");
|
|
PrintFormat("Config: Lookback=%d, Risk=%.1f/%.1f ATR", gLookback, gTargetSL_Mult, gTargetTP_Mult);
|
|
PrintFormat("Sessions: Asian %d-%d, London %d-%d, NY %d-%d", gAsianStart, gAsianEnd, gLondonStart, gLondonEnd, gNYStart, gNYEnd);
|
|
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
|
|
// Load Model with Header
|
|
bool LoadModelWithHeader(string filename)
|
|
{
|
|
int handle = FileOpen(filename, FILE_READ|FILE_BIN|FILE_COMMON);
|
|
if(handle == INVALID_HANDLE) { Print("Error opening model file."); return false; }
|
|
|
|
int version = FileReadInteger(handle);
|
|
if(version != 2) { Print("Error: Model version match (Expected 2)"); FileClose(handle); return false; }
|
|
|
|
gLookback = FileReadInteger(handle);
|
|
int topologyCnt = FileReadInteger(handle);
|
|
ArrayResize(GlobalTopology, topologyCnt);
|
|
for(int i=0; i<topologyCnt; i++) GlobalTopology[i] = FileReadInteger(handle);
|
|
|
|
gTargetTP_Mult = FileReadDouble(handle);
|
|
gTargetSL_Mult = FileReadDouble(handle);
|
|
|
|
gAsianStart = FileReadInteger(handle);
|
|
gAsianEnd = FileReadInteger(handle);
|
|
gLondonStart = FileReadInteger(handle);
|
|
gLondonEnd = FileReadInteger(handle);
|
|
gNYStart = FileReadInteger(handle);
|
|
gNYEnd = FileReadInteger(handle);
|
|
|
|
// Create Net with loaded Topology
|
|
if(CheckPointer(Net) != POINTER_INVALID) delete Net;
|
|
Net = new CNeuralNet(GlobalTopology, ACT_LEAKY_RELU);
|
|
|
|
// Load Weights
|
|
if(!Net.Load(handle, GlobalTopology)) { FileClose(handle); return false; }
|
|
|
|
FileClose(handle);
|
|
return true;
|
|
}
|
|
|
|
// Market Profile Calculation
|
|
void CalcProfile(const MqlRates &rates[], int start, int end, DailyProfile &out) {
|
|
if(start >= end) { out.valid=false; return; }
|
|
double minP = 999999, maxP = -1;
|
|
double totalVol = 0;
|
|
for(int i=start; i<end; i++) {
|
|
if(rates[i].low < minP) minP = rates[i].low;
|
|
if(rates[i].high > maxP) maxP = rates[i].high;
|
|
totalVol += (double)rates[i].tick_volume;
|
|
}
|
|
if(maxP <= minP) { out.valid=false; return; }
|
|
|
|
double point = _Point; if(point == 0) point = 0.0001;
|
|
int steps = (int)((maxP - minP) / point) + 1;
|
|
if(steps > 5000) steps = 5000;
|
|
double stepSize = (maxP - minP) / steps; if(stepSize == 0) stepSize = point;
|
|
|
|
double hist[]; ArrayResize(hist, steps); ArrayInitialize(hist, 0);
|
|
for(int i=start; i<end; i++) {
|
|
double avgP = (rates[i].open + rates[i].close + rates[i].high + rates[i].low)/4.0;
|
|
int idx = (int)((avgP - minP) / stepSize);
|
|
if(idx >= 0 && idx < steps) hist[idx] += (double)rates[i].tick_volume;
|
|
}
|
|
|
|
int pocIdx = 0; double maxVal = -1;
|
|
for(int i=0; i<steps; i++) { if(hist[i] > maxVal) { maxVal = hist[i]; pocIdx = i; } }
|
|
out.POC = minP + pocIdx * stepSize;
|
|
|
|
double vaVol = totalVol * 0.70; double curVol = maxVal;
|
|
int up = pocIdx, down = pocIdx;
|
|
while(curVol < vaVol) {
|
|
double vUp = (up < steps-1) ? hist[up+1] : 0;
|
|
double vDown = (down > 0) ? hist[down-1] : 0;
|
|
if(vUp > vDown) { if(up < steps-1) { up++; curVol += hist[up]; } else if(down > 0) { down--; curVol += hist[down]; } else break; }
|
|
else { if(down > 0) { down--; curVol += hist[down]; } else if(up < steps-1) { up++; curVol += hist[up]; } else break; }
|
|
}
|
|
out.VAH = minP + up * stepSize; out.VAL = minP + down * stepSize;
|
|
|
|
ArrayResize(out.Crests, 0); ArrayResize(out.Troughs, 0);
|
|
for(int i=2; i<steps-2; i++) {
|
|
double v = hist[i];
|
|
if(v > hist[i-1] && v > hist[i+1] && v > maxVal * 0.1) {
|
|
int s = ArraySize(out.Crests); ArrayResize(out.Crests, s+1); out.Crests[s] = minP + i * stepSize;
|
|
}
|
|
if(v < hist[i-1] && v < hist[i+1]) {
|
|
int s = ArraySize(out.Troughs); ArrayResize(out.Troughs, s+1); out.Troughs[s] = minP + i * stepSize;
|
|
}
|
|
}
|
|
out.valid = true;
|
|
}
|
|
|
|
// Precompute Data (Using Loaded Globals)
|
|
void PrecomputeData(const MqlRates &rates[], int total) {
|
|
int oldestIdx = total - 1;
|
|
datetime oldestTime = rates[oldestIdx].time;
|
|
baseTime = oldestTime - (oldestTime % 86400);
|
|
|
|
int numDays = (int)((rates[0].time - baseTime) / 86400) + 5;
|
|
ArrayResize(DayMap, numDays);
|
|
for(int i=0; i<numDays; i++) {
|
|
DayMap[i].Asian.valid = false; DayMap[i].Asian.H = -1; DayMap[i].Asian.L = 999999; DayMap[i].Asian.Volume = 0;
|
|
DayMap[i].London.valid = false; DayMap[i].London.H = -1; DayMap[i].London.L = 999999; DayMap[i].London.Volume = 0;
|
|
DayMap[i].NY.valid = false; DayMap[i].NY.H = -1; DayMap[i].NY.L = 999999; DayMap[i].NY.Volume = 0;
|
|
DayMap[i].Profile.valid = false;
|
|
}
|
|
ArrayResize(VWAPBuffer, total);
|
|
|
|
double list_AsianOR[], list_AsianTot[];
|
|
double list_LondonOR[], list_LondonTot[];
|
|
double list_NYOR[], list_NYTot[];
|
|
|
|
double sumPV_d=0, sumV_d=0, sumSqPV_d=0;
|
|
double sumPV_w=0, sumV_w=0, sumSqPV_w=0;
|
|
double sumPV_m=0, sumV_m=0, sumSqPV_m=0;
|
|
int currDay = -1; int currWeek = -1; int currMonth = -1;
|
|
|
|
for(int i=total-1; i>=0; i--) {
|
|
MqlDateTime dt; TimeToStruct(rates[i].time, dt);
|
|
int dayIdx = GetDayIndex(rates[i].time);
|
|
|
|
if(dt.day_of_year != currDay) { sumPV_d=0; sumV_d=0; sumSqPV_d=0; currDay = dt.day_of_year; }
|
|
int weekNum = (int)(rates[i].time / 604800);
|
|
if(weekNum != currWeek) { sumPV_w=0; sumV_w=0; sumSqPV_w=0; currWeek = weekNum; }
|
|
if(dt.mon != currMonth) { sumPV_m=0; sumV_m=0; sumSqPV_m=0; currMonth = dt.mon; }
|
|
|
|
double typPrice = (rates[i].high + rates[i].low + rates[i].close) / 3.0;
|
|
double vol = (double)rates[i].tick_volume;
|
|
|
|
sumPV_d += typPrice * vol; sumV_d += vol; sumSqPV_d += vol * typPrice * typPrice;
|
|
VWAPBuffer[i].vwap_d = (sumV_d > 0) ? sumPV_d / sumV_d : typPrice;
|
|
VWAPBuffer[i].std_d = MathSqrt(MathMax(0, (sumV_d > 0) ? (sumSqPV_d / sumV_d) - (VWAPBuffer[i].vwap_d * VWAPBuffer[i].vwap_d) : 0));
|
|
|
|
sumPV_w += typPrice * vol; sumV_w += vol; sumSqPV_w += vol * typPrice * typPrice;
|
|
VWAPBuffer[i].vwap_w = (sumV_w > 0) ? sumPV_w / sumV_w : typPrice;
|
|
VWAPBuffer[i].std_w = MathSqrt(MathMax(0, (sumV_w > 0) ? (sumSqPV_w / sumV_w) - (VWAPBuffer[i].vwap_w * VWAPBuffer[i].vwap_w) : 0));
|
|
|
|
sumPV_m += typPrice * vol; sumV_m += vol; sumSqPV_m += vol * typPrice * typPrice;
|
|
VWAPBuffer[i].vwap_m = (sumV_m > 0) ? sumPV_m / sumV_m : typPrice;
|
|
VWAPBuffer[i].std_m = MathSqrt(MathMax(0, (sumV_m > 0) ? (sumSqPV_m / sumV_m) - (VWAPBuffer[i].vwap_m * VWAPBuffer[i].vwap_m) : 0));
|
|
|
|
int h = dt.hour; int m = dt.min;
|
|
|
|
if(h >= gAsianStart && h < gAsianEnd) {
|
|
if(DayMap[dayIdx].Asian.H == -1 || rates[i].high > DayMap[dayIdx].Asian.H) DayMap[dayIdx].Asian.H = rates[i].high;
|
|
if(rates[i].low < DayMap[dayIdx].Asian.L) DayMap[dayIdx].Asian.L = rates[i].low;
|
|
DayMap[dayIdx].Asian.Volume += vol;
|
|
DayMap[dayIdx].Asian.valid = true;
|
|
if(((h - gAsianStart)*60 + m) < 30) {
|
|
if(DayMap[dayIdx].Asian.OR30_H == 0 || rates[i].high > DayMap[dayIdx].Asian.OR30_H) DayMap[dayIdx].Asian.OR30_H = rates[i].high;
|
|
if(DayMap[dayIdx].Asian.OR30_L == 0 || rates[i].low < DayMap[dayIdx].Asian.OR30_L) DayMap[dayIdx].Asian.OR30_L = rates[i].low;
|
|
DayMap[dayIdx].Asian.OR30_Vol += vol;
|
|
}
|
|
}
|
|
if(h >= gLondonStart && h < gLondonEnd) {
|
|
if(DayMap[dayIdx].London.H == -1 || rates[i].high > DayMap[dayIdx].London.H) DayMap[dayIdx].London.H = rates[i].high;
|
|
if(rates[i].low < DayMap[dayIdx].London.L) DayMap[dayIdx].London.L = rates[i].low;
|
|
DayMap[dayIdx].London.Volume += vol;
|
|
DayMap[dayIdx].London.valid = true;
|
|
if(((h - gLondonStart)*60 + m) < 30) {
|
|
if(DayMap[dayIdx].London.OR30_H == 0 || rates[i].high > DayMap[dayIdx].London.OR30_H) DayMap[dayIdx].London.OR30_H = rates[i].high;
|
|
if(DayMap[dayIdx].London.OR30_L == 0 || rates[i].low < DayMap[dayIdx].London.OR30_L) DayMap[dayIdx].London.OR30_L = rates[i].low;
|
|
DayMap[dayIdx].London.OR30_Vol += vol;
|
|
}
|
|
}
|
|
if(h >= gNYStart && h < gNYEnd) {
|
|
if(DayMap[dayIdx].NY.H == -1 || rates[i].high > DayMap[dayIdx].NY.H) DayMap[dayIdx].NY.H = rates[i].high;
|
|
if(rates[i].low < DayMap[dayIdx].NY.L) DayMap[dayIdx].NY.L = rates[i].low;
|
|
DayMap[dayIdx].NY.Volume += vol;
|
|
DayMap[dayIdx].NY.valid = true;
|
|
if(((h - gNYStart)*60 + m) < 30) {
|
|
if(DayMap[dayIdx].NY.OR30_H == 0 || rates[i].high > DayMap[dayIdx].NY.OR30_H) DayMap[dayIdx].NY.OR30_H = rates[i].high;
|
|
if(DayMap[dayIdx].NY.OR30_L == 0 || rates[i].low < DayMap[dayIdx].NY.OR30_L) DayMap[dayIdx].NY.OR30_L = rates[i].low;
|
|
DayMap[dayIdx].NY.OR30_Vol += vol;
|
|
}
|
|
}
|
|
}
|
|
|
|
int dayStartIdx = total-1;
|
|
int currentDayIdx = GetDayIndex(rates[total-1].time);
|
|
|
|
for(int i=total-1; i>=-1; i--) {
|
|
int d = (i>=0) ? GetDayIndex(rates[i].time) : -1;
|
|
if(d != currentDayIdx) {
|
|
if(currentDayIdx >= 0 && currentDayIdx < numDays) {
|
|
int idxStart = i + 1;
|
|
CalcProfile(rates, idxStart, idxStart + (dayStartIdx - idxStart + 1), DayMap[currentDayIdx].Profile);
|
|
|
|
if(DayMap[currentDayIdx].Asian.valid) {
|
|
ArrayResize(list_AsianOR, ArraySize(list_AsianOR)+1); list_AsianOR[ArraySize(list_AsianOR)-1] = DayMap[currentDayIdx].Asian.OR30_Vol;
|
|
ArrayResize(list_AsianTot, ArraySize(list_AsianTot)+1); list_AsianTot[ArraySize(list_AsianTot)-1] = DayMap[currentDayIdx].Asian.Volume;
|
|
}
|
|
if(DayMap[currentDayIdx].London.valid) {
|
|
ArrayResize(list_LondonOR, ArraySize(list_LondonOR)+1); list_LondonOR[ArraySize(list_LondonOR)-1] = DayMap[currentDayIdx].London.OR30_Vol;
|
|
ArrayResize(list_LondonTot, ArraySize(list_LondonTot)+1); list_LondonTot[ArraySize(list_LondonTot)-1] = DayMap[currentDayIdx].London.Volume;
|
|
}
|
|
if(DayMap[currentDayIdx].NY.valid) {
|
|
ArrayResize(list_NYOR, ArraySize(list_NYOR)+1); list_NYOR[ArraySize(list_NYOR)-1] = DayMap[currentDayIdx].NY.OR30_Vol;
|
|
ArrayResize(list_NYTot, ArraySize(list_NYTot)+1); list_NYTot[ArraySize(list_NYTot)-1] = DayMap[currentDayIdx].NY.Volume;
|
|
}
|
|
}
|
|
currentDayIdx = d; dayStartIdx = i;
|
|
}
|
|
}
|
|
AvgVol_Asian[0] = MathMean(list_AsianOR); AvgVol_Asian[1] = MathMean(list_AsianTot);
|
|
AvgVol_London[0] = MathMean(list_LondonOR); AvgVol_London[1] = MathMean(list_LondonTot);
|
|
AvgVol_NY[0] = MathMean(list_NYOR); AvgVol_NY[1] = MathMean(list_NYTot);
|
|
}
|
|
|
|
void OnDeinit(const int reason) {
|
|
if(CheckPointer(Net) != POINTER_INVALID) delete Net;
|
|
IndicatorRelease(handleEMA50); IndicatorRelease(handleEMA200); IndicatorRelease(handleATR_D1);
|
|
}
|
|
|
|
void OnTick()
|
|
{
|
|
datetime time = iTime(_Symbol, _Period, 0);
|
|
if(time == lastBarTime) return;
|
|
lastBarTime = time;
|
|
|
|
int histDepth = 50000;
|
|
MqlRates rates[];
|
|
ArraySetAsSeries(rates, true);
|
|
|
|
double ema50[], ema200[];
|
|
ArraySetAsSeries(ema50, true); ArraySetAsSeries(ema200, true);
|
|
|
|
if(CopyRates(_Symbol, PERIOD_H1, 0, histDepth, rates) < 2000 ||
|
|
CopyBuffer(handleEMA50, 0, 0, gLookback+1, ema50) < gLookback ||
|
|
CopyBuffer(handleEMA200, 0, 0, gLookback+1, ema200) < gLookback) return;
|
|
|
|
// Refresh features
|
|
int totalRates = ArraySize(rates);
|
|
PrecomputeData(rates, totalRates);
|
|
|
|
int featuresPerBar = 49;
|
|
double inputs[]; ArrayResize(inputs, gLookback * featuresPerBar);
|
|
|
|
for(int k=0; k<gLookback; k++) {
|
|
int p = k; // Index 0 is current bar
|
|
int off = k * featuresPerBar;
|
|
double c = rates[p].close;
|
|
|
|
int dayIdx = GetDayIndex(rates[p].time);
|
|
MqlDateTime pDt; TimeToStruct(rates[p].time, pDt);
|
|
int pHour = pDt.hour;
|
|
|
|
double aH=c, aL=c, aVol=0, aORH=c, aORL=c, aORVol=0;
|
|
int idxA = (pHour >= gAsianEnd) ? dayIdx : dayIdx - 1;
|
|
if(idxA>=0 && DayMap[idxA].Asian.valid) {
|
|
aH = DayMap[idxA].Asian.H; aL = DayMap[idxA].Asian.L; aVol = DayMap[idxA].Asian.Volume;
|
|
aORH = DayMap[idxA].Asian.OR30_H; aORL = DayMap[idxA].Asian.OR30_L; aORVol = DayMap[idxA].Asian.OR30_Vol;
|
|
}
|
|
double lH=c, lL=c, lVol=0, lORH=c, lORL=c, lORVol=0;
|
|
int idxL = (pHour >= gLondonEnd) ? dayIdx : dayIdx - 1;
|
|
if(idxL>=0 && DayMap[idxL].London.valid) {
|
|
lH = DayMap[idxL].London.H; lL = DayMap[idxL].London.L; lVol = DayMap[idxL].London.Volume;
|
|
lORH = DayMap[idxL].London.OR30_H; lORL = DayMap[idxL].London.OR30_L; lORVol = DayMap[idxL].London.OR30_Vol;
|
|
}
|
|
double nH=c, nL=c, nVol=0, nORH=c, nORL=c, nORVol=0;
|
|
int idxN = (pHour >= gNYEnd) ? dayIdx : dayIdx - 1;
|
|
if(idxN>=0 && DayMap[idxN].NY.valid) {
|
|
nH = DayMap[idxN].NY.H; nL = DayMap[idxN].NY.L; nVol = DayMap[idxN].NY.Volume;
|
|
nORH = DayMap[idxN].NY.OR30_H; nORL = DayMap[idxN].NY.OR30_L; nORVol = DayMap[idxN].NY.OR30_Vol;
|
|
}
|
|
|
|
inputs[off+0] = (c - aORH)/c * 1000; inputs[off+1] = (c - aORL)/c * 1000; inputs[off+2] = (AvgVol_Asian[0]>0)?(aORVol/AvgVol_Asian[0]):0;
|
|
inputs[off+3] = (c - aH)/c * 1000; inputs[off+4] = (c - aL)/c * 1000; inputs[off+5] = (AvgVol_Asian[1]>0)?(aVol/AvgVol_Asian[1]):0;
|
|
inputs[off+6] = (c - lORH)/c * 1000; inputs[off+7] = (c - lORL)/c * 1000; inputs[off+8] = (AvgVol_London[0]>0)?(lORVol/AvgVol_London[0]):0;
|
|
inputs[off+9] = (c - lH)/c * 1000; inputs[off+10] = (c - lL)/c * 1000; inputs[off+11] = (AvgVol_London[1]>0)?(lVol/AvgVol_London[1]):0;
|
|
inputs[off+12] = (c - nORH)/c * 1000; inputs[off+13] = (c - nORL)/c * 1000; inputs[off+14] = (AvgVol_NY[0]>0)?(nORVol/AvgVol_NY[0]):0;
|
|
inputs[off+15] = (c - nH)/c * 1000; inputs[off+16] = (c - nL)/c * 1000; inputs[off+17] = (AvgVol_NY[1]>0)?(nVol/AvgVol_NY[1]):0;
|
|
inputs[off+18] = (c - ema50[p])/ema50[p] * 1000.0;
|
|
inputs[off+19] = (c - ema200[p])/ema200[p] * 1000.0;
|
|
inputs[off+20] = (ema50[p] - ema200[p])/ema200[p] * 1000.0;
|
|
inputs[off+21] = (double)pDt.hour / 24.0;
|
|
inputs[off+22] = (double)((pDt.min/15)) / 4.0;
|
|
|
|
int mpIdx = dayIdx - 1;
|
|
double poc=c, vah=c, val=c;
|
|
double dCrest=0, dTrough=0;
|
|
if(mpIdx>=0 && DayMap[mpIdx].Profile.valid) {
|
|
poc = DayMap[mpIdx].Profile.POC; vah = DayMap[mpIdx].Profile.VAH; val = DayMap[mpIdx].Profile.VAL;
|
|
double minD = 999999;
|
|
for(int cx=0; cx<ArraySize(DayMap[mpIdx].Profile.Crests); cx++) {
|
|
double d = MathAbs(c - DayMap[mpIdx].Profile.Crests[cx]); if(d < minD) minD = d;
|
|
}
|
|
dCrest = (minD!=999999) ? minD : 0;
|
|
minD = 999999;
|
|
for(int tx=0; tx<ArraySize(DayMap[mpIdx].Profile.Troughs); tx++) {
|
|
double d = MathAbs(c - DayMap[mpIdx].Profile.Troughs[tx]); if(d < minD) minD = d;
|
|
}
|
|
dTrough = (minD!=999999) ? minD : 0;
|
|
}
|
|
inputs[off+23] = (c - poc)/c * 1000.0; inputs[off+24] = (c - vah)/c * 1000.0; inputs[off+25] = (c - val)/c * 1000.0;
|
|
inputs[off+26] = dCrest / c * 1000.0; inputs[off+27] = dTrough / c * 1000.0;
|
|
|
|
double std1_d = VWAPBuffer[p].std_d; double std1_w = VWAPBuffer[p].std_w; double std1_m = VWAPBuffer[p].std_m;
|
|
inputs[off+28] = (c - VWAPBuffer[p].vwap_d)/c * 1000.0;
|
|
inputs[off+29] = (c - (VWAPBuffer[p].vwap_d + std1_d))/c * 1000.0; inputs[off+30] = (c - (VWAPBuffer[p].vwap_d - std1_d))/c * 1000.0;
|
|
inputs[off+31] = (c - (VWAPBuffer[p].vwap_d + 2*std1_d))/c * 1000.0; inputs[off+32] = (c - (VWAPBuffer[p].vwap_d - 2*std1_d))/c * 1000.0;
|
|
inputs[off+33] = (c - (VWAPBuffer[p].vwap_d + 3*std1_d))/c * 1000.0; inputs[off+34] = (c - (VWAPBuffer[p].vwap_d - 3*std1_d))/c * 1000.0;
|
|
inputs[off+35] = (c - VWAPBuffer[p].vwap_w)/c * 1000.0;
|
|
inputs[off+36] = (c - (VWAPBuffer[p].vwap_w + std1_w))/c * 1000.0; inputs[off+37] = (c - (VWAPBuffer[p].vwap_w - std1_w))/c * 1000.0;
|
|
inputs[off+38] = (c - (VWAPBuffer[p].vwap_w + 2*std1_w))/c * 1000.0; inputs[off+39] = (c - (VWAPBuffer[p].vwap_w - 2*std1_w))/c * 1000.0;
|
|
inputs[off+40] = (c - (VWAPBuffer[p].vwap_w + 3*std1_w))/c * 1000.0; inputs[off+41] = (c - (VWAPBuffer[p].vwap_w - 3*std1_w))/c * 1000.0;
|
|
inputs[off+42] = (c - VWAPBuffer[p].vwap_m)/c * 1000.0;
|
|
inputs[off+43] = (c - (VWAPBuffer[p].vwap_m + std1_m))/c * 1000.0; inputs[off+44] = (c - (VWAPBuffer[p].vwap_m - std1_m))/c * 1000.0;
|
|
inputs[off+45] = (c - (VWAPBuffer[p].vwap_m + 2*std1_m))/c * 1000.0; inputs[off+46] = (c - (VWAPBuffer[p].vwap_m - 2*std1_m))/c * 1000.0;
|
|
inputs[off+47] = (c - (VWAPBuffer[p].vwap_m + 3*std1_m))/c * 1000.0; inputs[off+48] = (c - (VWAPBuffer[p].vwap_m - 3*std1_m))/c * 1000.0;
|
|
}
|
|
|
|
Net.FeedForward(inputs);
|
|
double results[]; Net.GetResults(results);
|
|
double signal = results[0];
|
|
|
|
double atrArray[2]; CopyBuffer(handleATR_D1, 0, 0, 2, atrArray);
|
|
double atrToUse = (atrArray[0] > atrArray[1]) ? atrArray[0] : atrArray[1];
|
|
double distTP = atrToUse * gTargetTP_Mult;
|
|
double distSL = atrToUse * gTargetSL_Mult;
|
|
|
|
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
Print("Signal: ", signal, " ATR: ", atrToUse);
|
|
|
|
if(signal > InpConfidence && !PositionSelect(_Symbol)) {
|
|
Trade.Buy(InpLotSize, _Symbol, 0, ask - distSL, ask + distTP, "NN Adv Buy");
|
|
} else if(signal < -InpConfidence && !PositionSelect(_Symbol)) {
|
|
Trade.Sell(InpLotSize, _Symbol, 0, bid + distSL, bid - distTP, "NN Adv Sell");
|
|
}
|
|
}
|