mql5/Experts/AdvancedPriceActionEA.mq5

423 行
20 KiB
MQL5
Raw パーマリンク 通常表示 履歴

2026-01-25 16:54:03 +00:00
//+------------------------------------------------------------------+
//| 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);
2026-01-26 17:18:04 +03:00
handleEMA50 = iMA(_Symbol, PERIOD_H1, 50, 0, MODE_EMA, PRICE_CLOSE);
handleEMA200 = iMA(_Symbol, PERIOD_H1, 200, 0, MODE_EMA, PRICE_CLOSE);
2026-01-25 16:54:03 +00:00
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;
2026-01-26 17:18:04 +03:00
Net = new CNeuralNet(GlobalTopology, ACT_LEAKY_RELU);
2026-01-25 16:54:03 +00:00
// 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);
2026-01-26 17:18:04 +03:00
if(CopyRates(_Symbol, PERIOD_H1, 0, histDepth, rates) < 2000 ||
2026-01-25 16:54:03 +00:00
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");
}
}