2026-06-05 22:00:59 +03:00
//+------------------------------------------------------------------+
//| Research.mq5 |
//| Copyright DNG® |
//| https://www.mql5.com/ru/users/dng |
//+------------------------------------------------------------------+
# property copyright " Copyright DNG® "
# property link " https://www.mql5.com/ru/users/dng "
# property version " 1.00 "
//+------------------------------------------------------------------+
//| Includes |
//+------------------------------------------------------------------+
# include "Trajectory.mqh"
# include <Trade\Trade.mqh>
# include <Trade\SymbolInfo.mqh>
# include <Indicators\Oscilators.mqh>
//+------------------------------------------------------------------+
//| Input parameters |
//+------------------------------------------------------------------+
input ENUM_TIMEFRAMES TimeFrame = PERIOD_H1 ;
//---
input group " ---- RSI ---- "
input int RSIPeriod = 14 ; //Period
input ENUM_APPLIED_PRICE RSIPrice = PRICE_CLOSE ; //Applied price
//---
input group " ---- CCI ---- "
input int CCIPeriod = 14 ; //Period
input ENUM_APPLIED_PRICE CCIPrice = PRICE_TYPICAL ; //Applied price
//---
input group " ---- ATR ---- "
input int ATRPeriod = 14 ; //Period
//---
input group " ---- MACD ---- "
input int FastPeriod = 12 ; //Fast
input int SlowPeriod = 26 ; //Slow
input int SignalPeriod = 9 ; //Signal
input ENUM_APPLIED_PRICE MACDPrice = PRICE_CLOSE ; //Applied price
input int Agents = 1 ;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
SState sState ;
STrajectory Base ;
STrajectory Buffer [ ] ;
STrajectory Frame [ 1 ] ;
CNet Agent ;
//---
float dError ;
datetime dtStudied ;
//---
CSymbolInfo Symb ;
CTrade Trade ;
//---
MqlRates Rates [ ] ;
CiRSI RSI ;
CiCCI CCI ;
CiATR ATR ;
CiMACD MACD ;
//---
CBufferFloat bState ;
CBufferFloat * Result ;
vector < float > AgentResult ;
double PrevBalance = 0 ;
double PrevEquity = 0 ;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit ( )
{
//---
if ( ! Symb . Name ( _Symbol ) )
return INIT_FAILED ;
Symb . Refresh ( ) ;
//---
if ( ! RSI . Create ( Symb . Name ( ) , TimeFrame , RSIPeriod , RSIPrice ) )
return INIT_FAILED ;
//---
if ( ! CCI . Create ( Symb . Name ( ) , TimeFrame , CCIPeriod , CCIPrice ) )
return INIT_FAILED ;
//---
if ( ! ATR . Create ( Symb . Name ( ) , TimeFrame , ATRPeriod ) )
return INIT_FAILED ;
//---
if ( ! MACD . Create ( Symb . Name ( ) , TimeFrame , FastPeriod , SlowPeriod , SignalPeriod , MACDPrice ) )
return INIT_FAILED ;
if ( ! RSI . BufferResize ( NBarInPattern ) | | ! CCI . BufferResize ( NBarInPattern ) | |
! ATR . BufferResize ( NBarInPattern ) | | ! MACD . BufferResize ( NBarInPattern ) )
{
PrintFormat ( " %s -> %d " , __FUNCTION__ , __LINE__ ) ;
return INIT_FAILED ;
}
//---
if ( ! Trade . SetTypeFillingBySymbol ( Symb . Name ( ) ) )
return INIT_FAILED ;
//--- load models
float temp ;
string filename = FileName + " Act.nnw " ;
if ( ! Agent . Load ( filename , temp , temp , temp , dtStudied , true ) )
{
PrintFormat ( " Can't load pretrained model " ) ;
return INIT_FAILED ;
}
//---
Agent . getResults ( Result ) ;
if ( Result . Total ( ) ! = NActions )
{
PrintFormat ( " The scope of the actor does not match the actions count (%d <> %d) " , NActions , Result . Total ( ) ) ;
return INIT_FAILED ;
}
AgentResult = vector < float > ::Zeros ( NActions ) ;
//---
Agent . GetLayerOutput ( 0 , Result ) ;
if ( Result . Total ( ) ! = ( NRewards + BarDescr * NBarInPattern + AccountDescr + TimeDescription + NActions ) )
{
PrintFormat ( " Input size of Actor doesn't match state description (%d <> %d) " , Result . Total ( ) , ( NRewards + BarDescr * NBarInPattern + AccountDescr + TimeDescription + NActions ) ) ;
return INIT_FAILED ;
}
//---
PrevBalance = AccountInfoDouble ( ACCOUNT_BALANCE ) ;
PrevEquity = AccountInfoDouble ( ACCOUNT_EQUITY ) ;
//---
return ( INIT_SUCCEEDED ) ;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit ( const int reason )
{
//---
LoadTotalBase ( ) ;
int total = ArraySize ( Buffer ) ;
if ( ArrayResize ( Buffer , total + 1 , 0 ) < 0 )
return ;
Buffer [ total ] = Base ;
printf ( " total %d " , MathMin ( total + 1 , MaxReplayBuffer ) ) ;
SaveTotalBase ( ) ;
delete Result ;
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick ( )
{
//---
if ( ! IsNewBar ( ) )
return ;
//---
int bars = CopyRates ( Symb . Name ( ) , TimeFrame , iTime ( Symb . Name ( ) , TimeFrame , 1 ) , NBarInPattern , Rates ) ;
if ( ! ArraySetAsSeries ( Rates , true ) )
return ;
//---
RSI . Refresh ( ) ;
CCI . Refresh ( ) ;
ATR . Refresh ( ) ;
MACD . Refresh ( ) ;
Symb . Refresh ( ) ;
Symb . RefreshRates ( ) ;
//--- History data
float atr = 0 ;
for ( int b = 0 ; b < ( int ) NBarInPattern ; b + + )
{
float open = ( float ) Rates [ 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 )
continue ;
//---
int shift = b * BarDescr ;
sState . state [ shift ] = ( float ) ( Rates [ b ] . close - open ) ;
sState . state [ shift + 1 ] = ( float ) ( Rates [ b ] . high - open ) ;
sState . state [ shift + 2 ] = ( float ) ( Rates [ b ] . low - open ) ;
sState . state [ shift + 3 ] = ( float ) ( Rates [ 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 ) ;
//--- Account description
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 < total ; i + + )
{
if ( PositionGetSymbol ( i ) ! = Symb . Name ( ) )
continue ;
double profit = PositionGetDouble ( POSITION_PROFIT ) ;
switch ( ( int ) PositionGetInteger ( POSITION_TYPE ) )
{
case POSITION_TYPE_BUY :
buy_value + = PositionGetDouble ( POSITION_VOLUME ) ;
buy_profit + = profit ;
break ;
case POSITION_TYPE_SELL :
sell_value + = PositionGetDouble ( POSITION_VOLUME ) ;
sell_profit + = profit ;
break ;
}
position_discount + = profit - ( current - PositionGetInteger ( POSITION_TIME ) ) * multiplyer * MathAbs ( profit ) ;
}
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 ) Rates [ 0 ] . time ;
//---
bState . Add ( ( float ) ( ( sState . account [ 0 ] - PrevBalance ) / PrevBalance ) ) ;
bState . Add ( ( float ) ( sState . account [ 1 ] / PrevBalance ) ) ;
bState . Add ( ( float ) ( ( sState . account [ 1 ] - PrevEquity ) / PrevEquity ) ) ;
bState . Add ( sState . account [ 2 ] ) ;
bState . Add ( sState . account [ 3 ] ) ;
bState . Add ( ( float ) ( sState . account [ 4 ] / PrevBalance ) ) ;
bState . Add ( ( float ) ( sState . account [ 5 ] / PrevBalance ) ) ;
bState . Add ( ( float ) ( sState . account [ 6 ] / PrevBalance ) ) ;
//--- Time label
double x = ( double ) Rates [ 0 ] . time / ( double ) ( D ' 2024.01 .01 ' - D ' 2023.01 .01 ' ) ;
bState . Add ( ( float ) MathSin ( 2.0 * M_PI * x ) ) ;
x = ( double ) Rates [ 0 ] . time / ( double ) PeriodSeconds ( PERIOD_MN1 ) ;
bState . Add ( ( float ) MathCos ( 2.0 * M_PI * x ) ) ;
x = ( double ) Rates [ 0 ] . time / ( double ) PeriodSeconds ( PERIOD_W1 ) ;
bState . Add ( ( float ) MathSin ( 2.0 * M_PI * x ) ) ;
x = ( double ) Rates [ 0 ] . time / ( double ) PeriodSeconds ( PERIOD_D1 ) ;
bState . Add ( ( float ) MathSin ( 2.0 * M_PI * x ) ) ;
//--- Reward to go
bState . Add ( float ( 1 - ( sState . account [ 0 ] - PrevBalance ) / PrevBalance ) ) ;
bState . Add ( float ( 0.1f - ( sState . account [ 1 ] - PrevEquity ) / PrevEquity ) ) ;
bState . Add ( 0 ) ;
//--- Prev action
bState . AddArray ( AgentResult ) ;
//---
if ( ! Agent . feedForward ( GetPointer ( bState ) , 1 , false , ( CBufferFloat * ) NULL ) )
return ;
//---
PrevBalance = sState . account [ 0 ] ;
PrevEquity = sState . account [ 1 ] ;
//---
vector < float > temp ;
Agent . getResults ( 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 ;
}
else
{
temp [ 3 ] - = temp [ 0 ] ;
temp [ 0 ] = 0 ;
}
float delta = MathAbs ( AgentResult - temp ) .Sum ( ) ;
AgentResult = temp ;
//--- buy control
if ( temp [ 0 ] < min_lot | | ( temp [ 1 ] * MaxTP * Symb . Point ( ) ) < = stops | | ( temp [ 2 ] * MaxSL * Symb . Point ( ) ) < = stops )
{
if ( buy_value > 0 )
CloseByDirection ( POSITION_TYPE_BUY ) ;
}
else
{
double buy_lot = min_lot + MathRound ( ( double ) ( temp [ 0 ] - min_lot ) / step_lot ) * step_lot ;
double buy_tp = Symb . NormalizePrice ( Symb . Ask ( ) + temp [ 1 ] * MaxTP * Symb . Point ( ) ) ;
double buy_sl = Symb . NormalizePrice ( Symb . Ask ( ) - temp [ 2 ] * MaxSL * Symb . Point ( ) ) ;
if ( buy_value > 0 )
TrailPosition ( POSITION_TYPE_BUY , buy_sl , buy_tp ) ;
if ( buy_value ! = buy_lot )
{
if ( buy_value > buy_lot )
ClosePartial ( POSITION_TYPE_BUY , buy_value - buy_lot ) ;
else
Trade . Buy ( buy_lot - buy_value , Symb . Name ( ) , Symb . Ask ( ) , buy_sl , buy_tp ) ;
}
}
//--- sell control
if ( temp [ 3 ] < min_lot | | ( temp [ 4 ] * MaxTP * Symb . Point ( ) ) < = stops | | ( temp [ 5 ] * MaxSL * Symb . Point ( ) ) < = stops )
{
if ( sell_value > 0 )
CloseByDirection ( POSITION_TYPE_SELL ) ;
}
else
{
double sell_lot = min_lot + MathRound ( ( double ) ( temp [ 3 ] - min_lot ) / step_lot ) * step_lot ; ;
double sell_tp = Symb . NormalizePrice ( Symb . Bid ( ) - temp [ 4 ] * MaxTP * Symb . Point ( ) ) ;
double sell_sl = Symb . NormalizePrice ( Symb . Bid ( ) + temp [ 5 ] * MaxSL * Symb . Point ( ) ) ;
if ( sell_value > 0 )
TrailPosition ( POSITION_TYPE_SELL , sell_sl , sell_tp ) ;
if ( sell_value ! = sell_lot )
{
if ( sell_value > sell_lot )
ClosePartial ( POSITION_TYPE_SELL , sell_value - sell_lot ) ;
else
Trade . Sell ( sell_lot - sell_value , Symb . Name ( ) , Symb . Bid ( ) , sell_sl , sell_tp ) ;
}
}
//---
int shift = BarDescr * ( NBarInPattern -1 ) ;
sState . rewards [ 0 ] = bState [ shift ] ;
sState . rewards [ 1 ] = bState [ shift + 1 ] -1.0f ;
if ( ( buy_value + sell_value ) = = 0 )
sState . rewards [ 2 ] - = ( float ) ( atr / PrevBalance ) ;
else
sState . rewards [ 2 ] = 0 ;
for ( ulong i = 0 ; i < NActions ; i + + )
sState . action [ i ] = AgentResult [ i ] ;
if ( ! Base . Add ( sState ) )
ExpertRemove ( ) ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+