Diskussion zum Artikel "Neuronale Netze leicht gemacht (Teil 52): Forschung mit Optimismus und Verteilungskorrektur" - Seite 2

 
Dmitriy Gizlyk #:

Mir ist ein Tippfehler im Code des Study.mq5 Expert Advisor aufgefallen

Die Dateien im Artikel sind aktualisiert worden.

 
Dmitry, warum eröffnet dieses Netzwerk alle Geschäfte mit genau 1 Lot, wenn es alle Tests trainiert, und versucht nicht, das Lot zu ändern? Es versucht nicht, Bruchteile von Lots zu setzen und will auch nicht mehr als 1 Lot setzen. Die Trainingsparameter für das Instrument EURUSD sind die gleichen wie die Ihren.
 
Viktor Kudriavtsev #:
Dmitry, warum eröffnet dieses Netzwerk alle Geschäfte mit genau 1 Lot, wenn es mit allen Tests trainiert, und versucht nicht, das Lot zu ändern? Es versucht nicht, Bruchteile von Lots zu setzen und will auch nicht mehr als 1 Lot setzen. Die Trainingsparameter für das Instrument EURUSD sind die gleichen wie die Ihren.

Auf der letzten Actor-Schicht verwenden wir Sigmoid als Aktivierungsfunktion, die die Werte im Bereich [0,1] begrenzt. Für TP und SL verwenden wir einen Multiplikator, um die Werte anzupassen. Die Losgröße wird nicht angepasst. Daher ist 1 Los der maximal mögliche Wert.

//--- Schicht 9
   if(!(descr = new CLayerDescription()))
      return false;
   descr.type = defNeuronSoftActorCritic;
   descr.count = NActions;
   descr.window_out = 32;
   descr.optimization = ADAM;
   descr.activation = SIGMOID;
   if(!actor.Add(descr))
     {
      delete descr;
      return false;
     }
 
Dmitriy Gizlyk #:

In der letzten Actor-Schicht verwenden wir eine Sigmoid-Aktivierungsfunktion, die die Werte auf den Bereich [0,1] begrenzt. Für TP und SL verwenden wir einen Multiplikator zur Anpassung der Werte. Die Losgröße wird nicht angepasst. Daher ist 1 Lot der maximal mögliche Wert.

Verstanden, vielen Dank.

 
ENJOY <3

//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
if(!IsNewBar())
zurück;
//---
int bars = CopyRates(Symb.Name(), TimeFrame, iTime(Symb.Name(), TimeFrame, 1), HistoryBars, Rates);
if(!ArraySetAsSeries(Kurse, true))
zurückgeben;
//---
RSI.Refresh();
CCI.Refresh();
ATR.Refresh();
MACD.Refresh();
Symb.Refresh();
Symb.RefreshRates();
//---
float atr = 0;
for(int b = 0; b < (int)HistoryBars; b++)
{
float open = (float)Raten[b].open;
float rsi = (float)RSI.Main(b);
float cci = (float)CCI.Main(b);
atr = (float)ATR.Main(b);
float macd = (float)MACD.Main(b);
float sign = (float)MACD.Signal(b);
if(rsi == EMPTY_VALUE || cci == EMPTY_VALUE || atr == EMPTY_VALUE || macd == EMPTY_VALUE || sign == EMPTY_VALUE)
fortfahren;
//---
int shift = b * BarDescr;
sState.state[shift] = (float)(Rates[b].close - open);
sState.state[shift + 1] = (float)(Kurse[b].high - open);
sState.state[shift + 2] = (float)(Kurse[b].low - open);
sState.state[shift + 3] = (float)(Kurse[b].tick_volume / 1000.0f);
sState.state[shift + 4] = rsi;
sState.state[shift + 5] = cci;
sState.state[shift + 6] = atr;
sState.state[shift + 7] = macd;
sState.state[shift + 8] = sign;
}
bState.AssignArray(sState.state);
//---
sState.account[0] = (float)AccountInfoDouble(ACCOUNT_BALANCE);
sState.account[1] = (float)AccountInfoDouble(ACCOUNT_EQUITY);
//---
double buy_value = 0, sell_value = 0, buy_profit = 0, sell_profit = 0;
double position_discount = 0;
double multiplyer = 1,0 / (60,0 * 60,0 * 10,0);
int total = PositionsTotal();
datetime current = TimeCurrent();
for(int i = 0; i < gesamt; i++)
{
if(PositionGetSymbol(i) != Symb.Name())
weiter;
double profit = PositionGetDouble(POSITION_PROFIT);
switch((int)PositionGetInteger(POSITION_TYPE))
{
Fall POSITION_TYPE_BUY:
buy_value += PositionGetDouble(POSITION_VOLUME);
buy_profit += Gewinn;
Pause;
Fall POSITION_TYPE_SELL:
sell_value += PositionGetDouble(POSITION_VOLUME);
sell_profit += profit;
Pause;
}
position_discount += profit - (current - PositionGetInteger(POSITION_TIME)) * Multiplikator * MathAbs(Gewinn);
}
sState.account[2] = (float)buy_value;
sState.account[3] = (float)sell_value;
sState.account[4] = (float)buy_profit;
sState.account[5] = (Float)sell_profit;
sState.account[6] = (float)position_discount;
sState.account[7] = (float)Kurse[0].Zeit;
//---
bAccount.Clear();
bAccount.Add((float)((sState.account[0] - PrevBalance) / PrevBalance));
bAccount.Add((float)(sState.account[1] / PrevBalance));
bAccount.Add((float)((sState.account[1] - PrevEquity) / PrevEquity));
bAccount.Add(sState.account[2]);
bAccount.Add(sState.account[3]);
bAccount.Add((float)(sState.account[4] / PrevBalance));
bAccount.Add((float)(sState.account[5] / PrevBalance));
bAccount.Add((float)(sState.account[6] / PrevBalance));
double x = (double)Raten[0].Zeit / (double)(D'2024.01.01.01' - D'2023.01.01');
bAccount.Add((float)MathSin(x != 0 ? 2.0 * M_PI * x : 0));
x = (double)Raten[0].Zeit / (double)PeriodSeconds(PERIOD_MN1);
bAccount.Add((float)MathCos(x != 0 ? 2.0 * M_PI * x : 0));
x = (double)Raten[0].Zeit / (double)PeriodeSekunden(PERIOD_W1);
bAccount.Add((float)MathSin(x != 0 ? 2.0 * M_PI * x : 0));
x = (double)Raten[0].Zeit / (double)PeriodeSekunden(PERIOD_D1);
bAccount.Add((float)MathSin(x != 0 ? 2.0 * M_PI * x : 0));
//---
if (bAccount.GetIndex() >= 0 && !bAccount.BufferWrite())
zurück;
//---
if (!Actor.feedForward(GetPointer(bState), 1, false, GetPointer(bAccount)))
zurück;
//---
PrevBalance = sState.account[0];
PrevEquity = sState.account[1];
//---
vector<float> temp;
Actor.getResults(temp);
float delta = MathAbs(ActorResult - temp).Sum();
ActorResult = temp;
//---
double min_lot = Symb.LotsMin();
double step_lot = Symb.LotsStep();
double stops = MathMax(Symb.StopsLevel(), 1) * Symb.Point();
if (temp[0] >= temp[3])
{
temp[0] -= temp[3];
temp[3] = 0;
}
sonst
{
temp[3] -= temp[0];
temp[0] = 0;
}
//--- Kontrolle kaufen
if (temp[0] < min_lot || (temp[1] * MaxTP * Symb.Point())) <= stops || (temp[2] * MaxSL * Symb.Point()) <= stops)
{
if (kauf_wert > 0)
CloseByDirection(POSITION_TYPE_BUY);
}
sonst
{
buy_lot = min_lot + MathRound((double)(temp[0] - min_lot) / step_lot) * step_lot;
buy_tp = NormalizeDouble(Symb.Ask() + temp[1] * MaxTP * Symb.Point(), Symb.Digits());
double buy_sl = NormalizeDouble(Symb.Ask() - temp[2] * MaxSL * Symb.Point(), Symb.Digits());
if (buy_value > 0)
TrailPosition(POSITION_TYPE_BUY, buy_sl, buy_tp);
if (kauf_wert != kauf_lot)
{
wenn (kauf_wert > kauf_lot)
ClosePartial(POSITION_TYPE_BUY, buy_value - buy_lot);
sonst
Trade.Buy(buy_lot - buy_value, Symb.Name(), Symb.Ask(), buy_sl, buy_tp);
}
}
//--- Kontrolle verkaufen
if (temp[3] < min_lot || (temp[4] * MaxTP * Symb.Point())) <= stops || (temp[5] * MaxSL * Symb.Point()) <= stops)
{
if (verkauf_wert > 0)
CloseByDirection(POSITION_TYPE_SELL);
}
sonst
{
double sell_lot = min_lot + MathRound((double)(temp[3] - min_lot) / step_lot) * step_lot;
double sell_tp = NormalizeDouble(Symb.Bid() - temp[4] * MaxTP * Symb.Point(), Symb.Digits());
double sell_sl = NormalizeDouble(Symb.Bid() + temp[5] * MaxSL * Symb.Point(), Symb.Digits());
if (verkauf_wert > 0)
TrailPosition(POSITION_TYPE_SELL, sell_sl, sell_tp);
if (verkauf_wert != verkauf_lot)
{
wenn (verkaufswert > verkauf_lot)
ClosePartial(POSITION_TYPE_SELL, sell_value - sell_lot);
sonst
Trade.Sell(sell_lot - sell_value, Symb.Name(), Symb.Bid(), sell_sl, sell_tp);
}
}
// Berechnung der anfänglichen Belohnungen
float iRewards = bAccount[0];
vector<float> log_prob;
Actor.GetLogProbs(log_prob);
// ATR auf den Bereich [0, 1] normalisieren
float minATR = -100.0; // Passen Sie diese Werte auf der Grundlage Ihrer Daten an
float maxATR = 100,0;
float norm_atr = (atr - minATR) / (maxATR - minATR);
// Gewichte für die Normalisierung definieren
float minGewicht = 0,0;
float maxGewicht = 1.0;
// Normalisierung der anfänglichen Belohnungen und der normalisierten ATR auf der Grundlage der Gewichte
float norm_iBelohnungen = (iBelohnungen - minGewicht) / (maxGewicht - minGewicht);
float norm_norm_atr = (norm_atr - minGewicht) / (maxGewicht - minGewicht);
// Berechnung der Strafe für nicht getätigte Geschäfte
double penalty = (buy_value + sell_value) == 0 ? (norm_norm_atr + atr / (PrevBalance + LogProbMultiplier)) : 0.0;
// Belohnungen und Log-Wahrscheinlichkeiten aktualisieren
for (ulong i = 0; i < temp.Size(); i++)
{
sState.action[i] = temp[i];
sState.log_prob[i] = log_prob[i];
}
// Inkrement auf Basis von log_prob_sum berechnen
float iRewards_increment = MathLog((float)PrevBalance);
// Anpassung der Belohnungen basierend auf der anfänglichen norm_iRewards
if (norm_iRewards != 0)
{
norm_iRewards += norm_norm_atr + iRewards_increment;
}
// Anwendung der Z-Score-Normalisierung auf norm_iRewards
float meanRewards = -10.0; // Berechne den Mittelwert der Belohnungen über die Zeit
float stdRewards = 10.0; // Berechnung der Standardabweichung der Belohnungen im Zeitverlauf
float normalisierte_iBelohnungen = (norm_iBelohnungen - meanBelohnungen) / stdBelohnungen;
// Potenztransformation anwenden, um die Datenverteilung zu verbessern (z. B. Box-Cox-Transformation)
float power = 0.5; // Anpassung des Power-Parameters nach Bedarf
float transformed_reward = (pow(1 + normalised_iRewards, power) - 1) / power;
// Exponentielle Transformation anwenden, um die Datenverteilung zu verbessern
float ZReward = (transformed_reward - (LogProbMultiplier)) / (5 - (LogProbMultiplier));
float M-Belohnung = MathLog10(ZR-Belohnung + 1);
float reward = (Mreward - (-1.0f)) / (0.4f - (-1.0f));
Quadratwurzeltransformation anwenden
Berechne die gemappten Werte zurück in den Bereich [1, 100]
float SRQTreward = sqrt(reward);
Drucken der Belohnungen und anderer Informationen
Print("Kaufwert: ", kauf_wert);
Print("Sell Value: ", sell_value);
Print("Temperatur: ", temp);
Print("Temperatur Größe: ", temp. Größe());
Print("iBelohnungen: ", iBelohnungen);
Print("Normalisierte ATR: ", norm_norm_atr);
Print("Normalisierte iBelohnungen: ", normalisierte_iBelohnungen);
Print("Transformierte Belohnung: ", transformed_reward);
Print("Trajektorie-Belohnung: ", ZR-Belohnung);
Print("MATHLOG: ", Mreward);
Print("Skalierte Belohnung: ", Belohnung);
Print("SRQT-Belohnung: ", SRQT-Belohnung);
Hinzufügen von Zustand und normalisierten Belohnungen zur Trajektorie
if (! Base.Add(sState, reward))
{
ExpertRemove(); Behandelt den Fall, dass das Hinzufügen zu Base fehlschlägt
}
}
//+------------------------------------------------------------------+



//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CreateDescriptions(CArrayObj *Schauspieler, CArrayObj *Kritik)
{
//---
CLayerDescription *descr;
//---
if(!actor)
{
actor = new CArrayObj();
if(!actor)
return false;
}
if(!critic)
{
critic = new CArrayObj();
if(!critic)
return false;
}
//--- Akteur
actor.Clear();
//--- Eingabeschicht
if(!(descr = new CLayerDescription()))
return false;
descr.type = defNeuronBaseOCL;
int prev_count = descr.count = (HistoryBars * BarDescr);
descr.window = 0;
descr.activation = Keine;
descr.optimisation = ADAM;
if(!actor.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 1
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronConvOCL;
prev_count = descr.count = prev_count - 1;
descr.window = 7;
descr.step = 3;
descr.window_out = 8;
descr.activation = LReLU;
descr.optimisation = ADAM;
if(!actor.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 2
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronConvOCL;
prev_count = descr.count = prev_count - 1;
descr.window = 5;
descr.step = 2;
descr.window_out = 8;
descr.activation = LReLU;
descr.optimisation = ADAM;
if(!actor.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 3
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronConvOCL;
prev_count = descr.count = prev_count - 1;
descr.window = 3;
descr.step = 1;
descr.window_out = 8;
descr.activation = LReLU;
descr.optimisation = ADAM;
if(!actor.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 4
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronBaseOCL;
descr.count = 1024;
descr.activation = LReLU;
descr.optimisation = ADAM;
if(!actor.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 5
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronBaseOCL;
prev_count = descr.count = 512;
descr.activation = LReLU;
descr.optimisation = ADAM;
if(!actor.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 6
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronConvOCL;
prev_count = descr.count = prev_count - 1;
descr.window = 6;
descr.step = 2;
descr.window_out = 8;
descr.activation = LReLU;
descr.optimisation = ADAM;
if(!actor.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 7
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronConvOCL;
prev_count = descr.count = prev_count - 1;
descr.window = 4;
descr.step = 2;
descr.window_out = 8;
descr.activation = LReLU;
descr.optimisation = ADAM;
if(!actor.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 8
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronConvOCL;
prev_count = descr.count = prev_count - 1;
descr.window = 2;
descr.step = 1;
descr.window_out = 8;
descr.activation = LReLU;
descr.optimisation = ADAM;
if(!actor.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 9
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronConvOCL;
prev_count = descr.count = prev_count;
descr.window = 8;
descr.step = 8;
descr.window_out = 8;
descr.activation = LReLU;
descr.optimisation = ADAM;
if(!actor.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 10
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronBatchNormOCL;
descr.count = prev_count;
descr.batch = 1000;
descr.activation = Keine;
descr.optimisation = ADAM;
if(!actor.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 11
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronBaseOCL;
descr.count = 1024;
descr.activation = LReLU;
descr.optimisation = ADAM;
if(!actor.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 12
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronBaseOCL;
prev_count = descr.count = 512;
descr.activation = LReLU;
descr.optimisation = ADAM;
if(!actor.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 13
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronConcatenate;
descr.count = LatentCount;
descr.window = prev_count;
descr.step = AccountDescr;
descr.optimise = ADAM;
descr.activation = SIGMOID;
if(!actor.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 14
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronBaseOCL;
descr.count = 1024;
descr.activation = LReLU;
descr.optimisation = ADAM;
if(!actor.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 15
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronBaseOCL;
prev_count = descr.count = 1024;
descr.activation = LReLU;
descr.optimisation = ADAM;
if(!actor.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 16
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronBaseOCL;
descr.count = prev_count;
descr.activation = LReLU;
descr.optimisation = ADAM;
if(!actor.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 17
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronSoftActorCritic;
descr.count = NActions;
descr.window_out = 32;
descr.optimise = ADAM;
descr.activation = SIGMOID;
if(!actor.Add(descr))
{
descr löschen;
return false;
}
//--- Kritisch
critic.Clear();
//--- Eingabeschicht
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronBaseOCL;
prev_count = descr.count = LatentCount;
descr.window = 0;
descr.activation = Keine;
descr.optimisation = ADAM;
if(!critic.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 1
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronConcatenate;
descr.count = 1024;
descr.window = prev_count;
descr.step = 6;
descr.optimise = ADAM;
descr.activation = LReLU;
if(!critic.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 2
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronBaseOCL;
descr.count = 1024;
descr.activation = LReLU;
descr.optimisation = ADAM;
if(!critic.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 3
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronBaseOCL;
descr.count = 1024;
descr.activation = LReLU;
descr.optimisation = ADAM;
if(!critic.Add(descr))
{
descr löschen;
return false;
}
//--- Schicht 4
if(!(descr = new CLayerDescription())))
return false;
descr.type = defNeuronBaseOCL;
descr.count = 1024;
descr.activation = LReLU;
descr.optimisation = ADAM;
if(!critic. Add(descr))
{
löschen descr;
return false;
}
--- Schicht 5
if(!( descr = new CLayerDescription())))
return false;
descr.type = defNeuronBaseOCL;
descr.count = 1;
descr.optimise = ADAM;
descr.activation = Keine;
if(!critic. Add(descr))
{
löschen descr;
return false;
}
//---
return true;
}
 
Danke
Dateien:
Dmtry.PNG  34 kb