|
| 1 | +# Trade Analysis with Tags |
| 2 | + |
| 3 | +A simple "Total Profit/Loss" number doesn't tell you *why* your strategy is performing the way it is. A profitable strategy might have one highly successful entry condition and one that consistently loses money. A losing strategy might be dragged down by a stop-loss that is too tight. |
| 4 | + |
| 5 | +To solve this, Stochastix includes a powerful **Tagging** system. You can attach one or more string "tags" to every entry and exit signal. The backtesting engine then aggregates performance metrics for each tag, allowing you to perform detailed performance attribution. |
| 6 | + |
| 7 | +## How to Tag Your Trades |
| 8 | + |
| 9 | +The `$this->entry()` and `$this->exit()` methods in your `AbstractStrategy` both accept an optional final parameter: `enterTags` and `exitTags`, respectively. This parameter can be a single string or an array of strings. |
| 10 | + |
| 11 | +Let's look at a practical example. Imagine a strategy that can enter long for two reasons: an EMA crossover or an oversold RSI. It can exit for three reasons: an opposite EMA cross (the main exit signal), a take-profit level, or a stop-loss. |
| 12 | + |
| 13 | +```php |
| 14 | +// --- In onBar() --- |
| 15 | + |
| 16 | +// Condition 1: EMA Crossover Entry |
| 17 | +if ($emaFast->crossesOver($emaSlow)) { |
| 18 | + $this->entry( |
| 19 | + direction: DirectionEnum::Long, |
| 20 | + orderType: OrderTypeEnum::Market, |
| 21 | + quantity: '0.5', |
| 22 | + enterTags: 'ema_cross' // Tagging the entry reason |
| 23 | + ); |
| 24 | +} |
| 25 | + |
| 26 | +// Condition 2: RSI Oversold Entry |
| 27 | +if ($rsi[0] < 30 && $rsi[1] >= 30) { |
| 28 | + $this->entry( |
| 29 | + direction: DirectionEnum::Long, |
| 30 | + orderType: OrderTypeEnum::Market, |
| 31 | + quantity: '0.5', |
| 32 | + enterTags: ['rsi_oversold', 'mean_reversion_signal'] // Using multiple tags |
| 33 | + ); |
| 34 | +} |
| 35 | + |
| 36 | + |
| 37 | +// --- Exit Logic --- |
| 38 | +$openPosition = $this->orderManager->getPortfolioManager()->getOpenPosition($this->context->getCurrentSymbol()); |
| 39 | +if ($openPosition) { |
| 40 | + // Exit Condition 1: Main Signal (EMA cross down) |
| 41 | + if ($emaFast->crossesUnder($emaSlow)) { |
| 42 | + $this->exit($openPosition->quantity, exitTags: 'exit_signal_cross'); |
| 43 | + } |
| 44 | + |
| 45 | + // Exit Condition 2: Stop-Loss (logic handled elsewhere, just showing the tag) |
| 46 | + // For example, a trailing stop might be hit. |
| 47 | + if ($shouldExitForStopLoss) { |
| 48 | + $this->exit($openPosition->quantity, exitTags: 'stop_loss'); |
| 49 | + } |
| 50 | +} |
| 51 | +``` |
| 52 | + |
| 53 | +## Analyzing Tag Performance |
| 54 | + |
| 55 | +After the backtest is complete, the `statistics` object in the results file will contain two special sections: `enterTagStats` and `exitTagStats`. |
| 56 | + |
| 57 | +These sections provide a complete performance breakdown for each tag you used. |
| 58 | + |
| 59 | +**Example `enterTagStats` from a results file:** |
| 60 | + |
| 61 | +```json |
| 62 | +"enterTagStats": [ |
| 63 | + { |
| 64 | + "label": "ema_cross", |
| 65 | + "trades": 52, |
| 66 | + "totalProfit": 1850.75, |
| 67 | + "wins": 30, |
| 68 | + "losses": 22 |
| 69 | + }, |
| 70 | + { |
| 71 | + "label": "rsi_oversold", |
| 72 | + "trades": 15, |
| 73 | + "totalProfit": -400.25, |
| 74 | + "wins": 4, |
| 75 | + "losses": 11 |
| 76 | + } |
| 77 | +] |
| 78 | +``` |
| 79 | + |
| 80 | +### Answering Key Questions with Tags |
| 81 | + |
| 82 | +This data allows you to answer critical questions about your strategy's logic: |
| 83 | + |
| 84 | +* **"Which of my entry signals is actually profitable?"** |
| 85 | + *In the example above, trades entered because of `"ema_cross"` were highly profitable (`+1850.75`), while trades entered because of `"rsi_oversold"` were a net loss (`-400.25`). This tells you to focus on improving or removing the RSI entry condition.* |
| 86 | + |
| 87 | +* **"Is my stop-loss strategy helping or hurting?"** |
| 88 | + *By analyzing the `exitTagStats` for your `'stop_loss'` tag, you can see the total P&L of all trades that were closed by it. If the total loss from stop-outs is greater than the profits preserved, your stop-loss might be too tight or poorly placed.* |
| 89 | + |
| 90 | +* **"Which exit condition performs best?"** |
| 91 | + *You can compare the `averageProfitPercentage` and `totalProfit` for trades tagged with `'take_profit'` versus those with `'exit_signal_cross'` to see which exit logic captures more profit.* |
| 92 | + |
| 93 | +### A Note on Multiple Tags |
| 94 | + |
| 95 | +If a single trade has multiple tags (e.g., `['rsi_oversold', 'mean_reversion_signal']`), its profit and loss will be included in the statistics for **both** the `'rsi_oversold'` tag and the `'mean_reversion_signal'` tag. This is important to remember when analyzing the data, as the sum of `totalProfit` across all tags may not equal the overall total profit of the strategy if trades are multi-tagged. |
0 commit comments