This guide describes how to develop trading strategies using Python in the QuantDinger platform. QuantDinger provides a flexible execution environment that supports data access, indicator calculation, and signal generation.
## 1. Overview
Strategies in QuantDinger operate based on the **Signal Provider** mode. The system executes your Python script, which is expected to process market data (a DataFrame) and output trading signals.
The execution flow is as follows:
1.**Input**: The system injects a `df` (Pandas DataFrame) containing OHLCV data into your script environment.
2.**Processing**: You use Python (`pandas`, `numpy`) to calculate indicators and define `buy`/`sell` logic.
3.**Output**: You construct a specific `output` dictionary containing plot data and signals.
---
## 2. Environment & Data
Your script runs in a sandboxed Python environment.
### 2.1 Pre-imported Libraries
The following libraries are available by default (do not `import` them):
*`pd` (pandas)
*`np` (numpy)
### 2.2 Input Data (`df`)
A Pandas DataFrame variable named `df` is automatically available in the global scope. It contains the historical market data for the selected symbol and timeframe.
**Columns:**
*`time`: Timestamp (datetime or int, depending on context, usually localized)
*`open`: Open price (float)
*`high`: High price (float)
*`low`: Low price (float)
*`close`: Close price (float)
*`volume`: Trading volume (float)
**Example:**
```python
# Access closing prices
closes=df['close']
# Calculate a Simple Moving Average (SMA)
sma_20=df['close'].rolling(20).mean()
```
---
## 3. Developing a Strategy
A standard strategy script consists of three parts:
You **MUST** create two boolean Series in the `df` or as standalone variables, named `buy` and `sell`.
*`True` indicates a signal trigger.
*`False` indicates no signal.
**Important: Edge Triggering**
To avoid repeated signals on consecutive candles (which might lead to multiple orders depending on backend config), it is best practice to use **edge-triggered** signals (signal only on the moment the condition becomes true).
Rolling calculations (like `rolling(14)`) produce `NaN` values at the beginning of the data.
* **Rule**: Always handle `NaN`s before generating signals.
* **Fix**: Use `.fillna(0)` or `.fillna(False)` depending on context.
### 5.2 Look-ahead Bias
The system executes trades based on the signal generated at the *close* of a bar.
* The backtester typically executes the order at the **Open** of the **Next Bar**.
* Your signal logic should rely on `close` (current completed bar) or `shift(1)` (previous bar). Do not use `shift(-1)`.
### 5.3 Performance
Avoid iterating over the DataFrame rows (`for i in range(len(df)): ...`) for calculation logic. It is slow.
* **Bad**: Loop to calculate SMA.
* **Good**: `df['close'].rolling(...)`.
* **Exception**: Constructing the `buy_marks`/`sell_marks` list usually requires a list comprehension, which is acceptable for visual output.
### 5.4 Debugging
Since you cannot see `print()` output easily in some execution modes, check the backend logs (`backend_api_python/logs/app.log`) if your strategy fails to load.
* Common error: `KeyError` (wrong column name).
* Common error: `ValueError` (arrays must be same length). Ensure `plots` data matches `df` length.