Skip to content

Commit 4eb7832

Browse files
committed
docs: position sizing and plotting
1 parent caee6f6 commit 4eb7832

File tree

3 files changed

+248
-0
lines changed

3 files changed

+248
-0
lines changed

.vitepress/config.mts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ export default defineConfig({
3030
{ text: 'Anatomy of a Strategy', link: '/anatomy' },
3131
{ text: 'Using Indicators', link: '/using-indicators' },
3232
{ text: 'Placing Orders', link: '/placing-orders' },
33+
{ text: 'Position Sizing', link: '/position-sizing' },
34+
{ text: 'Plotting & Visualization', link: '/plotting' },
3335
]
3436
}
3537
],

plotting.md

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
# Plotting & Visualization
2+
3+
A picture is worth a thousand words, and in backtesting, a chart is worth a thousand data points. Stochastix includes a powerful plotting system that allows you to overlay your indicators directly onto the results chart, making it easy to debug your logic and analyze your strategy's behavior.
4+
5+
## How Plotting Works
6+
7+
You define your plots within the `defineIndicators()` method of your strategy, immediately after you define the indicator you wish to plot. The system works by linking a `PlotDefinition` to an indicator instance using the unique key you provided to the `$this->addIndicator()` method.
8+
9+
The primary method for this is `$this->definePlot()`.
10+
11+
## The `definePlot()` Method
12+
13+
This helper method, available in `AbstractStrategy`, allows you to configure how an indicator should be rendered.
14+
15+
```php
16+
protected function definePlot(
17+
string $indicatorKey,
18+
string $name,
19+
bool $overlay,
20+
array $plots,
21+
array $annotations = []
22+
): self
23+
```
24+
25+
**Parameters:**
26+
27+
* `indicatorKey`: **Must match** the key you used in `$this->addIndicator()`. This tells Stochastix which indicator's data to use for this plot.
28+
* `name`: A human-readable name that will appear in the chart's legend (e.g., "EMA (20)").
29+
* `overlay`: A boolean.
30+
* `true`: The plot will be drawn on top of the main price (candlestick) chart. Use this for price-based indicators like Moving Averages or Bollinger Bands.
31+
* `false`: The plot will be rendered in a separate pane below the main chart. Use this for oscillators like RSI or MACD.
32+
* `plots`: An array of plot components (like `Line` or `Histogram`) that define the series to be drawn from the indicator's data.
33+
* `annotations`: An array of static plot components, like horizontal lines.
34+
35+
## Defining What to Plot
36+
37+
The `$plots` and `$annotations` arrays accept special plot component objects that describe what to draw.
38+
39+
### `Line`
40+
41+
Draws a simple line graph. This is the most common component.
42+
43+
44+
* `key`: The specific data series from the indicator to plot. For simple indicators, this is almost always `'value'`. For multi-value indicators like MACD, this could be `'macd'` or `'signal'`.
45+
* `color`: An optional hex or rgba color string.
46+
47+
```php
48+
use Stochastix\Domain\Plot\Series\Line;
49+
50+
new Line(key: 'value', color: '#4e79a7')
51+
```
52+
53+
### `Histogram`
54+
55+
Draws a histogram (bar chart), often used for MACD histograms or volume.
56+
57+
58+
* `key`: The data series from the indicator to render as a histogram (e.g., `'hist'` for MACD).
59+
* `color`: An optional hex or rgba color string.
60+
61+
```php
62+
use Stochastix\Domain\Plot\Series\Histogram;
63+
64+
new Histogram(key: 'hist', color: 'rgba(178, 181, 190, 0.5)')
65+
```
66+
67+
### `HorizontalLine` (Annotation)
68+
69+
Draws a static horizontal line across a plot pane. This is an annotation, not a data series plot.
70+
71+
72+
* `value`: The y-axis value where the line should be drawn.
73+
* `color`: An optional color string.
74+
* `style`: The line style, from `HorizontalLineStyleEnum::Solid`, `Dashed`, or `Dotted`.
75+
76+
```php
77+
use Stochastix\Domain\Plot\Annotation\HorizontalLine;
78+
use Stochastix\Domain\Plot\Enum\HorizontalLineStyleEnum;
79+
80+
new HorizontalLine(value: 0, style: HorizontalLineStyleEnum::Dashed)
81+
```
82+
83+
## Complete Examples
84+
85+
Here’s how you would use these components in your `defineIndicators()` method.
86+
87+
### Example 1: Plotting EMAs on the Price Chart
88+
89+
This example plots two EMAs directly on top of the price candles.
90+
91+
```php
92+
protected function defineIndicators(): void
93+
{
94+
$this
95+
// 1. Define the fast EMA indicator
96+
->addIndicator(
97+
'ema_fast',
98+
new TALibIndicator(TALibFunctionEnum::Ema, ['timePeriod' => $this->emaFastPeriod])
99+
)
100+
// 2. Define the plot for the fast EMA
101+
->definePlot(
102+
indicatorKey: 'ema_fast', // Link to the indicator above
103+
name: "EMA ({$this->emaFastPeriod})",
104+
overlay: true, // Draw on the main price chart
105+
plots: [
106+
new Line(key: 'value', color: '#4e79a7'), // Plot its 'value' series
107+
]
108+
)
109+
// 3. Define the slow EMA indicator
110+
->addIndicator(
111+
'ema_slow',
112+
new TALibIndicator(TALibFunctionEnum::Ema, ['timePeriod' => $this->emaSlowPeriod])
113+
)
114+
// 4. Define the plot for the slow EMA
115+
->definePlot(
116+
indicatorKey: 'ema_slow',
117+
name: "EMA ({$this->emaSlowPeriod})",
118+
overlay: true,
119+
plots: [
120+
new Line(key: 'value', color: '#f28e2b'),
121+
]
122+
);
123+
}
124+
```
125+
126+
### Example 2: Plotting MACD in a Separate Pane
127+
128+
This example, adapted from the `SampleStrategy`, shows how to plot the multi-value MACD indicator in its own pane below the price chart.
129+
130+
```php
131+
protected function defineIndicators(): void
132+
{
133+
$this
134+
// 1. Define the MACD indicator
135+
->addIndicator(
136+
'macd',
137+
new TALibIndicator(TALibFunctionEnum::Macd, [
138+
'fastPeriod' => 12,
139+
'slowPeriod' => 26,
140+
'signalPeriod' => 9
141+
])
142+
)
143+
// 2. Define the plot for the MACD
144+
->definePlot(
145+
indicatorKey: 'macd', // Link to the indicator above
146+
name: 'MACD (12, 26, 9)',
147+
overlay: false, // Draw in a separate pane
148+
plots: [
149+
new Line(key: 'macd', color: '#2962FF'),
150+
new Line(key: 'signal', color: '#FF6D00'),
151+
new Histogram(key: 'hist', color: 'rgba(178, 181, 190, 0.5)'),
152+
],
153+
annotations: [
154+
// Add a dashed line at the zero level for reference
155+
new HorizontalLine(value: 0, style: HorizontalLineStyleEnum::Dashed)
156+
]
157+
);
158+
}
159+
```

position-sizing.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Position Sizing
2+
3+
Proper position sizing is one of the most critical components of a successful trading strategy. Rather than trading a fixed number of contracts or shares, many strategies calculate their position size based on the current portfolio value and a predefined risk tolerance.
4+
5+
This guide will walk you through a common approach: calculating the trade quantity based on a fixed percentage of your available capital.
6+
7+
## Accessing Your Capital
8+
9+
Before you can calculate how much to trade, you need to know how much capital is available. This information is held by the `PortfolioManager`. You can access it from within your strategy via the `OrderManager`.
10+
11+
The `$this->orderManager` property (available in `AbstractStrategy`) gives you access to the `getPortfolioManager()` method, which in turn has a `getAvailableCash()` method.
12+
13+
```php
14+
// Get the PortfolioManager
15+
$portfolioManager = $this->orderManager->getPortfolioManager();
16+
17+
// Get the available cash as a high-precision string
18+
$availableCash = $portfolioManager->getAvailableCash();
19+
```
20+
21+
## Calculating Trade Quantity
22+
23+
Let's say you want to size your position to be equivalent to 2% of your available cash. Here is the step-by-step process, which should be performed inside your `onBar()` method.
24+
25+
### Step 1: Define Your Risk Percentage
26+
27+
First, define what percentage of your capital you want to allocate to this trade. It's often best to define this as an `#[Input]` property so you can easily configure it.
28+
29+
```php
30+
use Stochastix\Domain\Strategy\Attribute\Input;
31+
32+
class MyStrategy extends AbstractStrategy
33+
{
34+
#[Input(description: 'Stake amount as a percentage of capital', min: 0.001, max: 1.0)]
35+
private float $stakeAmount = 0.02; // Our 2% risk
36+
37+
// ...
38+
}
39+
```
40+
41+
### Step 2: Calculate the Cash to Allocate
42+
43+
Inside `onBar()`, get your available cash and multiply it by your stake amount. We use `bcmul` to maintain precision.
44+
45+
```php
46+
$availableCash = $this->orderManager->getPortfolioManager()->getAvailableCash();
47+
48+
// Calculate the amount of cash to use for this trade
49+
$stakeInCash = bcmul($availableCash, (string) $this->stakeAmount);
50+
```
51+
52+
### Step 3: Convert Cash to Asset Quantity
53+
54+
To determine the quantity of the asset to trade, you must divide the allocated cash by the asset's current price.
55+
56+
It is crucial to perform two sanity checks here:
57+
1. Ensure the current price is not zero to prevent a division-by-zero error.
58+
2. Ensure the final calculated quantity is large enough to be a valid trade.
59+
60+
```php
61+
// Get the current close price from the $bars object
62+
$currentClose = $bars->close[0];
63+
64+
// --- Sanity Checks ---
65+
if ($currentClose === null || bccomp((string) $currentClose, '0') <= 0) {
66+
// Price is invalid, cannot calculate quantity.
67+
// You might want to log this.
68+
return;
69+
}
70+
71+
// --- Calculate Quantity ---
72+
$tradeQuantity = bcdiv($stakeInCash, (string) $currentClose);
73+
74+
// --- Final Sanity Check ---
75+
if (bccomp($tradeQuantity, '0.000001') < 0) {
76+
// Quantity is too small to be a meaningful trade.
77+
return;
78+
}
79+
80+
// Now, $tradeQuantity is ready to be used in an entry order.
81+
$this->entry(
82+
direction: DirectionEnum::Long,
83+
orderType: OrderTypeEnum::Market,
84+
quantity: $tradeQuantity
85+
);
86+
```
87+
This entire calculation logic is demonstrated in the sample strategy provided with the framework.

0 commit comments

Comments
 (0)