Could you hire me? Contact me if you like what I’ve done in this article and think I can create value for your company with my skills.

January 20, 2009 / by Zsolt Soczó

Amikor egy metódus nem a helyén lakik

Az utóbbi pár hétben rendkívül intenzíven egy programot írok – egy Automated Trading System-et, így mondják ezeket angolul. Azaz egy olyan programot, amely real-time tőzsdei adatok alapján automatikusan döntéseket hoz, ad-vesz. Persze a dolog a valóságban elképesztően bonyolult tud lenni, de programozási gyakorlatnak mindenképpen érdekes.

A rendszer részleteiről egyelőre nem akarok írni, majd ha működik, beszélek róla – bár lehet, hogy pont akkor nem kellene, mi? :)

No, a lényeg, hogy az ilyen rendszereket az ember csak akkor indít el, ha nagyon hosszú múltbeli adatokon végigpróbálva elég jó a nyereség/veszteség aránya, és nem csinál zsinórban annyi veszteséget, ami már pszichológialiag fáj, vagy akár le is nullázza az erre szánt pénzt.
Ezt a tesztelést hívják backtest-nek. Ehhez adatok kellenek, amit persze pénzért adnak, de ez már csak ilyen, ha ez ember pénzt akar keresni, ahhoz be is kell fektetni.
Nekem most már van több mint 10 évnyi perces adatom a legnagyobb likviditású futures-ökhöz (S&P 500 E-Mini, Nasdaq E-Mini, stb.).
Jöhet a szakma. A backtest írásakor kialakult a következő kódrészlet:

class BackTestSession
{

for (int i = 0; i < bars.Count; i++) { foreach (TradingAlgorithm alg in algs) { StepOne(alg, i); } } private void StepOne(TradingAlgorithm alg, int i) { if (!alg.InLong && !alg.InShort) { decimal entryPrice; TradeActionReason reason = alg.WantToBuyLong(i, out entryPrice); if (reason != TradeActionReason.None) { return; } reason = alg.WantToSellShort(i, out entryPrice); if (reason != TradeActionReason.None) { return; } return; } if (alg.InLong) { TradeActionReason reason = alg.WantToSellLong(i); if (reason != TradeActionReason.None) { return; } } if (alg.InShort) { TradeActionReason reason = alg.WantToCoverShort(i); if (reason != TradeActionReason.None) { return; } } return; } ... } [/source] Ez a kód messziről bűzlik. Mi a gond vele? Nem jó helyen lakik. Figyeljük meg, hogy egyfolytában egy másik típuson (TradingAlgorithm) végez műveleteket, átnyúlkál oda adatokért és műveleteket végezve rajta. Ez egy code smell a refactoringok házatáján, amire megoldás, ha elköltöztetjük a metódust a helyére. Move method refactoring. [source='C#'] class BackTestSession { for (int i = 0; i < bars.Count; i++) { foreach (TradingAlgorithm alg in algs) { alg.StepOne(i); } } } class TradingAlgorithm { public void StepOne(int i) { if (!InLong && !InShort) { decimal entryPrice; TradeActionReason reason = WantToBuyLong(i, out entryPrice); if (reason != TradeActionReason.None) { return; } reason = WantToSellShort(i, out entryPrice); if (reason != TradeActionReason.None) { return; } return; } if (InLong) { TradeActionReason reason = WantToSellLong(i); if (reason != TradeActionReason.None) { return; } } if (InShort) { TradeActionReason reason = WantToCoverShort(i); if (reason != TradeActionReason.None) { return; } } return; } } [/source] Látható a különbség? Sokkal direktebb lett a kód, oda került a metódus, ahová való. Erről szól az első GRASP pattern, az Information Expert.

Következő refactoring lenne az out paraméterek kiirtása, lecserélése member változóra. Erre még a VS is ad refactoring támogatást.

És most jön a shameless plug (bár nem ezért kezdem el írni a cikket, de ki nem hagynám a lehetőséget :): A Netacademiában márciusban lesz újra Design Patterns tanfolyamom, ahol az objektumorientált programozás praktikáit mutatom meg 4 napban, ilyen egyszerűeket mint a fenti, és sokkal bonyolultabbakat is. A régi tananyagot átírom a következő hetekben, kiegészítve .NET Fw. 3.5-ös példákkal (WCF-ben és WPF-ben nagyon szép példákat látni a patternekre).

Could you hire me? Contact me if you like what I’ve done in this article and think I can create value for your company with my skills.