1) zhermetyzował wszystko co się da - sporo pracy bo wszelkie zmienne globalne które są wywoływane bezpośrednio w rozmaitych funkcjach muszą być skonsolidowane i przekazywane jako parametr lub wyliczane jako zmienne lokalne,
2) Żeby się nie pogubić w kodzie długim jak papier toaletowy, rozdzieliłbym to na oddzielne pliki dołączane przez #include - każdy robot oddzielnie na tyle na ile się da. To też wymaga zmian i uporządkowania kodu - każdy z nich ma swój init(), start() i deinit() - trzeba je odpowiednio pozmieniać.
Niby proste ale często w nich jest niezły śmietnik, a w samym start() są rzeczy które powinny być raczej w init().
Np:
init()

start()

deinit()

Nie wspominając o kolejności kodu, nazwenictwie i przesłanianiu zmiennych...
3) ustandaryzował wszystko co się da, ograniczył do minimum ilość zmiennych globalnych, wsadził te które muszą pozostać globalne, a są specyficzne dla każdego robota do oddzielnych tabelek, a jakby się dało to najlepiej do jednej wielowymiarowej. Też kupa ręcznej roboty. Ale jak uda się to sprowadzić do czegoś w postaci initRobot1(robot1set); doRobot1(robot1set); deinitRobot1(robot1set) to mamy już jakąś protezę obiektów ;-)
4) I teraz jest zasadnicza sprawa - inwentaryzacja zleceń. Każdy z nich musi umieć rozpoznać swoje. Tutaj raczej nie obędzie się bez własnej bazy danych.
EDIT: można je rozgraniczyć numerami magic. Choć są i tacy brokerzy co śledzą te numery i robią im numery ;-)
Mam coś takiego co sprawdza pulę zleceń, i podlicza dla każdej postaci tego samego robota i nieźle odciska swój piętno na czasie wykonywania testów - dynamiczna alokacja pamięci. Coś za coś, nie ma nic za darmo...
A potem debuggował każdego robota oddzielnie bo razem to koszmar…
Aha - to co wyjdzie na backtestach nie będzie możliwe do uzyskania w rzeczywistości. Choćby przez czas jaki jest potrzebny na obsługę zleceń.
Jeżeli 5 robotów każdy po kolei ma coś zrobić ze zleceniami to w testerze pójdzie to gładko, a w rzeczywistości taka kolejka może trwać kilka minut, a w tym czasie rynek może zrobić bardzo dużo. Szczególnie jeżeli będą requoty lub inne zakłócenia. Z tego powodu unikałbym odczekiwania i powtarzania zleceń jak coś nie tak - lepiej wyskoczyć i poczekać na następną pętelkę zwalniając kolejkę innym.
I odpada praca na tikach, szczególnie jak ma pracować na wielu parach.
Są tickery do popychania kodu, albo można zrobić po prostu:
Kod: Zaznacz cały
start() {
While(!IsStopped()) {
for (int i=0;i<maxRobots;i++)
switch (i) {
case 0: doRobot1(robot1set); break;
case 1: doRobot2(robot2set); break;
...
}
Sleep (500);
}
}

Na szczęście w MQL4 istnieje pewna forma wskaźnika (pointer) - przez parametr funkcji:
Kod: Zaznacz cały
funkcja(double& wszystkieZmienneFunkcji[]) {
wszystkieZmienneFunkcji[3] = (wszystkieZmienneFunkcji[0] + wszystkieZmienneFunkcji[1]) * wszystkieZmienneFunkcji[2];
}
I na koniec nie zdziwiłbym się gdyby backtest takiego kodu trwał tygodniami. Zwłaszcza jak nie zrobi się w kodzie przełączników wyłączających to czego nie trzeba liczyć za każdym razem w teście albo będzie się niepotrzebnie liczyło to samo wielokrotnie. Np. Symbol() ;-) Albo niepotrzebne za to powtarzane w każdej pętelce pisanie/czytanie pliku ze zmiennymi...
Optymalizacja kodu się kłania i mam tu na myśli optymalizację pod kątem zdarzeń, a nie stricte matematyczną.
Choćby te if (warunek1) if (warunek2) if (warunek3) zamiast if (warunek 1 && warunek 2 && warunek 3) - zaczynamy od warunku który odrzuci najwięcej przypadków… Oczywiście to ma sens gdy te warunki to coś więcej niż zmienne typu bool albo proste dodawanie/odejmowanie/porównanie gotowych wartości.
Albo np. MarketInfo(symbol,MODE_STOPLEVEL) - w realu należy to sprawdzać za każdym razem bo brokerzy czasami tym manipulują. W testerze wystarczy raz w init() bo to się nie zmienia. Oczywiście to przykład - nie każdy robot jest na to wrażliwy.