|
| 1 | +# Advanced Order Management |
| 2 | + |
| 3 | +Beyond simple market orders, a robust trading strategy needs to manage its risk and adapt to changing conditions. Stochastix provides built-in mechanisms for both protective stops and dynamic order cancellation, allowing for more sophisticated trade management. |
| 4 | + |
| 5 | +## Stop-Loss and Take-Profit Orders |
| 6 | + |
| 7 | +A critical component of risk management is defining an exit point *before* you enter a trade. The `$this->entry()` method includes optional `stopLossPrice` and `takeProfitPrice` parameters to automate this process. |
| 8 | + |
| 9 | +```php |
| 10 | +$currentPrice = '3000.0'; |
| 11 | +$slPrice = '2940.0'; // Stop-loss at -2% |
| 12 | +$tpPrice = '3150.0'; // Take-profit at +5% |
| 13 | + |
| 14 | +$this->entry( |
| 15 | + direction: DirectionEnum::Long, |
| 16 | + orderType: OrderTypeEnum::Market, |
| 17 | + quantity: '0.5', |
| 18 | + stopLossPrice: $slPrice, |
| 19 | + takeProfitPrice: $tpPrice |
| 20 | +); |
| 21 | +``` |
| 22 | + |
| 23 | +When you provide these parameters, you are not creating pending `STOP` or `LIMIT` orders in the traditional sense. Instead, you are attaching metadata to the position. |
| 24 | + |
| 25 | +### Realistic Intra-Bar Execution |
| 26 | + |
| 27 | +The backtesting engine uses this metadata to simulate a more realistic execution model. On every bar *after* the entry, the engine will check if the bar's `high` or `low` price crossed your specified levels. |
| 28 | + |
| 29 | +* If you are **long**: |
| 30 | + * The engine checks if the bar's `low` was less than or equal to the `stopLossPrice`. |
| 31 | + * It checks if the bar's `high` was greater than or equal to the `takeProfitPrice`. |
| 32 | +* If you are **short**: |
| 33 | + * The engine checks if the bar's `high` was greater than or equal to the `stopLossPrice`. |
| 34 | + * It checks if the bar's `low` was less than or equal to the `takeProfitPrice`. |
| 35 | + |
| 36 | +If either condition is met, a market order is immediately created and executed at the stop/take-profit price, and the position is closed within that same bar. This is a more accurate simulation than waiting for the close of the bar, as it reflects how SL/TP orders work in live markets. |
| 37 | + |
| 38 | +## Programmatic Order Cancellation |
| 39 | + |
| 40 | +Strategies that use `Limit` or `Stop` orders to enter positions may need to cancel those orders if market conditions change. For example, if a limit order to buy a dip has not been filled and the market starts to trend down strongly, you may want to retract the order to avoid a bad entry. |
| 41 | + |
| 42 | +This is possible with the `$this->cancelOrder()` method. |
| 43 | + |
| 44 | +### Step 1: Place a Named Order |
| 45 | + |
| 46 | +To cancel a pending order, you must first give it a unique identifier when you create it. This is done using the `clientOrderId` parameter. |
| 47 | + |
| 48 | +```php |
| 49 | +// In onBar(), we decide to place a limit order to buy a dip. |
| 50 | +$limitPrice = '2800.0'; |
| 51 | + |
| 52 | +$this->entry( |
| 53 | + direction: DirectionEnum::Long, |
| 54 | + orderType: OrderTypeEnum::Limit, |
| 55 | + quantity: '0.5', |
| 56 | + price: $limitPrice, |
| 57 | + clientOrderId: 'my-long-dip-buy' // Give the order a unique name |
| 58 | +); |
| 59 | +``` |
| 60 | +This order is now sitting in the `OrderManager`'s pending order book, waiting for its price to be met. |
| 61 | + |
| 62 | +### Step 2: Cancel the Order on a New Condition |
| 63 | + |
| 64 | +On a subsequent bar, your strategy might detect a new condition (e.g., a trend indicator has turned bearish) and decide that the previous dip-buying idea is no longer valid. You can then use `cancelOrder()` with the same `clientOrderId`. |
| 65 | + |
| 66 | +```php |
| 67 | +// On a later bar... |
| 68 | +$trendIndicator = $this->getIndicatorSeries('my_trend_indicator'); |
| 69 | + |
| 70 | +// If the trend has turned bearish, we must cancel our pending buy order. |
| 71 | +if ($trendIndicator[0] < $trendIndicator[1]) { |
| 72 | + $this->cancelOrder('my-long-dip-buy'); |
| 73 | +} |
| 74 | +``` |
| 75 | + |
| 76 | +This removes the order from the pending book, ensuring it will not be executed even if the price later drops to `$2800`. |
0 commit comments