Ecco cosa si può fare con OpenCL direttamente in MetaTrader 5 senza alcuna DLL - pagina 4
Ti stai perdendo delle opportunità di trading:
- App di trading gratuite
- Oltre 8.000 segnali per il copy trading
- Notizie economiche per esplorare i mercati finanziari
Registrazione
Accedi
Accetti la politica del sito e le condizioni d’uso
Se non hai un account, registrati
Sì, ho un po' di familiarità con OCL, ne sono consapevole. Non dovete caricare l'intero EA nella mappa, lasciate che carichino alcuni frammenti di codice parallelo, di solito sono una percentuale dell'intero codice.
Allora, perché vedo solo i core della CPU (Core i5, 8 core - 8 agenti) quando ottimizzo quando ho NVIDIA 780GTX?
Usate OpenCL nel vostro codice?
Molto probabilmente pensate che tutto il vostro codice debba essere caricato sulla scheda grafica. Il che non è vero.
Consiglio vivamente di leggere il nostro articolo su OpenCL in MetaTrader 5 dove tutto è spiegato in dettaglio come funziona:
Per ottenere un'accelerazione significativa, è necessario inviare l'intero consulente alla GPU, ma per questo è necessario scrivere il proprio tester.
Ecco un esempio di un tale tester, una rete neurale con logica di trading, codice OCL:
//Функция для ядра
string GPU_kernel( int hl1NeuronCount,
int hl2NeuronCount,
int sampleCount,
int signalCount)
{
return
(
"#define HL1Count " + ( string )hl1NeuronCount + " \r\n"
"#define HL2Count " + ( string )hl2NeuronCount + " \r\n"
//------------------------------------------------------------------------------------
"#define NeuronSensitivity " + ( string )NeuronSensitivity_P + " \r\n"
//------------------------------------------------------------------------------------
"#define sampleCount " + ( string )sampleCount + " \r\n"
//------------------------------------------------------------------------------------
"#define signalCount " + ( string )signalCount + " \r\n"
//------------------------------------------------------------------------------------
"#define StrArrSaSize " + ( string )( sizeof (ArrSample) / sizeof ( float )) + "\r\n"
"typedef struct{float C[StrArrSaSize];} ArrSa; \r\n"
//------------------------------------------------------------------------------------
"#define StrArrWeSize " + ( string )( sizeof (ArrWe) / sizeof ( float )) + " \r\n"
"typedef struct{float C[StrArrWeSize];} ArrWe; \r\n"
//------------------------------------------------------------------------------------
"#define StrArrCrSize " + ( string )( sizeof (ArrCr) / sizeof ( float )) + " \r\n"
"typedef struct{float C[StrArrCrSize];}ArrCr; \r\n"
//------------------------------------------------------------------------------------
"#define Spread " + ( string )(Spread_P * Point ()) + " \r\n"
//------------------------------------------------------------------------------------
"#define Point " + ( string ) Point () + " \r\n"
"#define SL " + ( string )(StopLoss_P * Point ()) + " \r\n"
"#define TP " + ( string )(TakeProfit_P * Point ()) + " \r\n"
//------------------------------------------------------------------------------------
" \r\n"
"__kernel void Work(__global ArrSa *Sample, \r\n"
" __global ArrWe *Weights, \r\n"
" __global ArrCr *Result) \r\n"
"{ \r\n"
" int thread = get_global_id(0); \r\n"
" \r\n"
" //------------------Переменные нейронной сети---------------------------------\r\n"
" float nHL1 [HL1Count]; // Нейроны первого скрытого слоя \r\n"
" float nHL2 [HL2Count]; // Нейроны второго скрытого слоя \r\n"
" ArrWe parametr = Weights[thread]; // Параметры системы \r\n"
" int cnt_W = 0; // счетчик весов \r\n"
" float out = 0.0; // выход сети \r\n"
" \r\n"
" //-------------------Переменные для торговли----------------------------------\r\n"
" float temp = 0.0; // для временного хранения чего нибудь \r\n"
" \r\n"
" //---параметры цены \r\n"
" float priceASK = 0.0; // текущая Ask цена \r\n"
" float priceBID = 0.0; // текущая Bid цена \r\n"
" float pricePrevHighASK = 0.0; // максимум предыдущей свечи Ask \r\n"
" float pricePrevHighBID = 0.0; // максимум предыдущей свечи Bid \r\n"
" float pricePrevLowASK = 0.0; // минимум предыдущей свечи Ask \r\n"
" float pricePrevLowBID = 0.0; // минимум предыдущей свечи Bid \r\n"
" \r\n"
" float posType = 0.0; // тип сделки: \r\n"
" // 1.0 - buy, \r\n"
" //-1.0 - sell; \r\n"
" // 0.0 - нет открытой сделки \r\n"
" float posPriceClose = 0.0; \r\n"
" float posPriceClosePrevHi = 0.0; \r\n"
" float posPriceClosePrevLo = 0.0; \r\n"
" \r\n"
" //-----------------Текущие показатели позиции---------------------------------\r\n"
" float posPriceSL = 0.0; // цена StopLoss открытой сделки \r\n"
" float posPriceTP = 0.0; // цена TakeProfit открытой сделки \r\n"
" \r\n"
" //--------------------Статистика торговли-------------------------------------\r\n"
" int StTradeProfitCount = 0; // кол-во приб. сделок \r\n"
" int StTradeLossCount = 0; // кол-во уб. сделок \r\n"
" \r\n"
" int StTradeLossSeries = 0; // текущая серия убыточных ордеров \r\n"
" int StTradeMaxLossSer = 0; // самая длинная серия уб.ордеров \r\n"
" \r\n"
" //-----------------------Тут прогон по истории--------------------------------\r\n"
" for(int hist = 0;hist < sampleCount;hist++) \r\n"
" { \r\n"
" cnt_W = 0; \r\n"
" //---------------Обработаем первый скрытый слой-----------------------------\r\n"
" //Добавим смещение точек насыщения нейрона: (+b) \r\n"
" for(int u = 0;u < HL1Count;u++) \r\n"
" { \r\n"
" nHL1[u] = parametr.C[cnt_W]; \r\n"
" cnt_W++; \r\n"
" } \r\n"
" \r\n"
" //Сумма произведений нейронов предыдущего слоя и их весов: \r\n"
" // (+w1*x1+...+wn*xn) для каждого нейрона \r\n"
" for(int u = 0;u < HL1Count;u++) \r\n"
" { \r\n"
" for(int i = 0;i < signalCount;i++) \r\n"
" { \r\n"
" nHL1[u] += Sample[hist].C[i + 3] * parametr.C[cnt_W]; \r\n"
" cnt_W++; \r\n"
" } \r\n"
" } \r\n"
" \r\n"
" //Посчитаем функцию активации для каждого скрытого нейрона \r\n"
" for(int u = 0;u < HL1Count;u++) \r\n"
" { \r\n"
" nHL1[u] = 5.0 * nHL1[u] / (1.0 + fabs(4.02 * nHL1[u])); \r\n"
" } \r\n"
" \r\n"
" //---------------Обработаем второй скрытый слой-----------------------------\r\n"
" //Добавим смещение точек насыщения нейрона: (+b) \r\n"
" for(int u = 0;u < HL2Count;u++) \r\n"
" { \r\n"
" nHL2[u] = parametr.C[cnt_W]; \r\n"
" cnt_W++; \r\n"
" } \r\n"
" \r\n"
continuazione del codice:
" // (+w1*x1+...+wn*xn) для каждого нейрона \r\n"
" for(int u = 0;u < HL2Count;u++) \r\n"
" { \r\n"
" for(int i = 0;i < HL1Count;i++) \r\n"
" { \r\n"
" nHL2[u] += nHL1[i] * parametr.C[cnt_W]; \r\n"
" cnt_W++; \r\n"
" } \r\n"
" } \r\n"
" \r\n"
" //Посчитаем функцию активации для каждого скрытого нейрона \r\n"
" for(int u = 0;u < HL2Count;u++) \r\n"
" { \r\n"
" nHL2[u] = 5.0 * nHL2[u] / (1.0 + fabs(4.02 * nHL2[u])); \r\n"
" } \r\n"
" \r\n"
" //-----------------Обработаем выходной слой---------------------------------\r\n"
" //Добавим смещение точек насыщения нейрона: (+b) \r\n"
" out = parametr.C[cnt_W]; \r\n"
" cnt_W++; \r\n"
" \r\n"
" //Сумма произведений нейронов предыдущего слоя и их весов: \r\n"
" // (+w1*x1+...+wn*xn) для каждого нейрона \r\n"
" for(int i = 0;i < HL2Count;i++) \r\n"
" { \r\n"
" out += nHL2[i] * parametr.C[cnt_W]; \r\n"
" cnt_W++; \r\n"
" } \r\n"
" //==========================================================================\r\n"
" \r\n"
" \r\n"
" //==========================================================================\r\n"
" priceASK = Sample[hist].C[0] + Spread; \r\n"
" priceBID = Sample[hist].C[0]; \r\n"
" \r\n"
" pricePrevHighASK = Sample[hist].C[1] + Spread; \r\n"
" pricePrevHighBID = Sample[hist].C[1]; \r\n"
" \r\n"
" pricePrevLowASK = Sample[hist].C[2] + Spread; \r\n"
" pricePrevLowBID = Sample[hist].C[2]; \r\n"
" \r\n"
" //-----------------проверка условий на выход из рынка-----------------------\r\n"
" // если есть открытая поза \r\n"
" if(posType != 0.0) \r\n"
" { \r\n"
" if(posType == 1.0) \r\n"
" { \r\n"
" posPriceClose = priceBID; \r\n"
" posPriceClosePrevHi = pricePrevHighBID; \r\n"
" posPriceClosePrevLo = pricePrevLowBID; \r\n"
" } \r\n"
" else \r\n"
" { \r\n"
" posPriceClose = priceASK; \r\n"
" posPriceClosePrevHi = pricePrevHighASK; \r\n"
" posPriceClosePrevLo = pricePrevLowASK; \r\n"
" } \r\n"
" \r\n"
" \r\n"
" // может уже сработал SL? \r\n"
" if(posType * (posPriceSL - posPriceClose) >= 0.0 || \r\n"
" posType * (posPriceSL - posPriceClosePrevLo) >= 0.0) \r\n"
" { \r\n"
" // на одну убыточную сделку больше \r\n"
" StTradeLossCount++; \r\n"
" // текущая серия убыточных сделок увеличилась \r\n"
" StTradeLossSeries++; \r\n"
" // если серия уб. сделок больше чем в истори, то запомним \r\n"
" StTradeMaxLossSer = (StTradeMaxLossSer < StTradeLossSeries) ? \r\n"
" StTradeLossSeries : StTradeMaxLossSer; \r\n"
" // позиция закрыта \r\n"
" posType = 0.0; \r\n"
" } \r\n"
" // нет, SL не сработал \r\n"
" else \r\n"
" { \r\n"
" // может уже сработал TP? \r\n"
" if(posType * (posPriceClose - posPriceTP) >= 0.0 || \r\n"
" posType * (posPriceClosePrevHi - posPriceTP) >= 0.0) \r\n"
" { \r\n"
" // на одну прибыльную сделку больше \r\n"
" StTradeProfitCount++; \r\n"
" // текущая серия убыточных сделок закончилась \r\n"
" StTradeLossSeries = 0; \r\n"
" // позиция закрыта \r\n"
" posType = 0.0; \r\n"
" } \r\n"
" } \r\n"
" \r\n"
" } \r\n"
" //--------------------------------------------------------------------------\r\n"
" \r\n"
" \r\n"
" //-----------------проверка сигнала на вход в рынок-------------------------\r\n"
" // если нет открытых поз проверим возможность открытия \r\n"
" if(posType == 0.0 && hist < (sampleCount - 1)) \r\n"
" { \r\n"
" // если есть сигнал на покупку \r\n"
" if(NeuronSensitivity < out) \r\n"
" { \r\n"
" posPriceTP = priceASK + TP; \r\n"
" posPriceSL = priceASK - SL; \r\n"
" posType = 1.0; \r\n"
" } \r\n"
" // если есть сигнал на продажу \r\n"
" if(out < -NeuronSensitivity) \r\n"
" { \r\n"
" posPriceSL = priceBID + SL; \r\n"
" posPriceTP = priceBID - TP; \r\n"
" posType = -1.0; \r\n"
" } \r\n"
" } \r\n"
" } \r\n"
" \r\n"
" \r\n"
" //----------------------------------------------------------------------------\r\n"
" float Profit = ((float)StTradeProfitCount*TP)-((float)StTradeLossCount*SL); \r\n"
" Result[thread].C[0] = Profit; \r\n"
" Result[thread].C[1] = -StTradeMaxLossSer; \r\n"
"} \r\n"
);
}
//————————————————————————————————————————————————————————————————————————————————————————————————
Questa è una dimostrazione non solo dei calcoli della GPU nel codice MQL5, ma anche delle capacità grafiche del terminale:
Il codice sorgente completo come script è allegato. Il bug su OpenCL 1.2 è stato risolto.
la continuazione del codice:
A proposito, è possibile inviare codice a OCL in qualche modo sotto forma di file, piuttosto che come voce di riga? Altrimenti sembra un po' inquietante.
A proposito, è possibile inviare il codice a OCL non come un foglio riga per riga, ma in qualche modo come un file? Sembra un po' inquietante.
È importante notare che ora, alla fine del 2016, è già possibile rivendicare la presenza di OpenCL nei sistemi di destinazione.
Anche se non c'è una GPU, OpenCL verrà eseguito sulla CPU usando tutti i core. Questo è l'aspetto del set di dispositivi:
OpenCL Device #1: CPU GenuineIntel Intel(R) Xeon(R) CPU E5-2690 v3 @ 2.60 GHz with OpenCL 1.2 (24 units, 2598 MHz, 32680 Mb, version 2117.13 (sse2,avx), rating 85)
Il terminale seleziona automaticamente il dispositivo più veloce in base alla valutazione delle prestazioni. È anche possibile selezionare manualmente qualsiasi dispositivo tramite la funzione CLContextCreate.
Sfortunatamente, dimenticatevi di OpenCL su Windows XP. E i sistemi operativi a 32 bit in generale - è l'anno 2017.
Più sgradevole è la situazione con Nvidia, che sta essenzialmente sabotando lo standard OpenCL e non implementando OpenCL 2.0. Prima ha sabotato l'implementazione di OpenCL 1.2, ora OpenCL 2.0. Lo sta facendo per promuovere la propria implementazione di CUDA, il che danneggia l'intera comunità.
Inoltre, Nvidia abbassa deliberatamente la precisione nelle sue schede per giocatori per limitare il loro uso in matematica e stimolare l'acquisto di schede specializzate (Tesla).
In questo contesto AMD sembra essere vincente non solo per la loro matematica chiaramente più veloce (le fattorie minerarie su AMD sono solitamente costruite), ma anche per la loro strategia di standard aperti (si sono aperti molto e stanno spingendo nel dominio pubblico). L'introduzione di OpenCL 2.0 nelle schede AMD ha portato questa specifica molto vicino alle capacità di CUDA e ora non ha senso gettare le basi per CUDA.