Writing Your First Trading Strategy
This guide will walk you through creating a simplified trading strategy using Super Algorithm, demonstrating the core concepts and implementation details. We recommend you read this guide, and the rest of the documentation to get a full understanding of the framework and it's capabilities.
Prerequisites
We will be using talipp for computing indicators:
pip install talipp
Creating Your Strategy
Create a new file named sma_sample_strategy.py
and implement your strategy following these steps:
1. Set Up the Basic Structure
First, import the necessary modules and create your strategy class:
from superalgorithm.strategy import BaseStrategy
from superalgorithm.types import Bar, OrderType, PositionType
from talipp.indicators import SMA
class SMAStrategy(BaseStrategy):
pass
2. Initialize Your Strategy
Implement the init
method to:
- Set up event handlers for data aggregates
- Initialize your indicators
def init(self):
# Listen for 5-minute interval events
self.on("5m", self.on_5)
# Initialize Simple Moving Average indicators
self.sma = SMA(14) # Fast SMA with 14 periods
self.sma_slow = SMA(200) # Slow SMA with 200 periods
3. Handle Time Intervals
There are two ways to receive data in your strategy:
- The
on_tick(bar: Bar)
method receives updates from all configured DataSources, including partial updates for Bars. - The
on(<timeframe>, bar: Bar)
method receives updates from all configured DataSources for each completed bar.
For this example implement the on_5
method to process 5-minute bars.
async def on_5(self, bar: Bar):
# Update indicators with new data
self.sma.add(bar.close)
self.sma_slow.add(bar.close)
# Execute trading logic
await self.trade_logic()
TIP
Since we are using only one DataSource, we know that the bar will come from that source. If you are using multiple DataSources, you could check bar.source_id
to identify which bar triggered the event.
4. Implement Trading Logic
Create the trade_logic
method to:
- Check for sufficient data
- Generate buy/sell signals
- Execute trades
The BaseStrategy comes with two convenience functions to access your data at any point:
- The current bars' ohlcv:
self.get("BTC/USDT", "5m") -> OHLCV
- List of ohlcv values including the current bars' value:
self.data("BTC/USDT", "5m") -> List[OHLCV]
async def trade_logic(self):
# Ensure we have enough data and our indicators are populated
if len(self.sma_slow) < 2 or self.sma_slow[-2] is None:
return
close = self.get("BTC/USDT", "5m").close
# Generate signals
buy = self.sma[-2] < self.sma_slow[-2] and self.sma[-1] > self.sma_slow[-1]
sell = self.sma[-2] > self.sma_slow[-2] and self.sma[-1] < self.sma_slow[-1]
# Execute trades based on signals
if buy:
await self.open("BTC/USDT", PositionType.LONG, 0.1, OrderType.LIMIT, close)
if sell:
await self.close("BTC/USDT", PositionType.LONG, 0.1, OrderType.LIMIT, close)
TIP
When submitting trades, we refer to either opening or closing a position. In the example above, we open
a long position and then close
a long position. In the same context you could open
and close
a short position. You can also open
a long and short position at the same time, given your exchange supports this.
5. Implement Required Methods
Add the required on_tick
method, even if unused:
async def on_tick(self, bar: Bar):
pass
Complete Implementation
Here's the complete strategy implementation:
from superalgorithm.strategy import BaseStrategy
from superalgorithm.types import Bar, OrderType, PositionType
from talipp.indicators import SMA
class SMAStrategy(BaseStrategy):
def init(self):
self.on("5m", self.on_5)
self.sma = SMA(14)
self.sma_slow = SMA(200)
async def on_5(self, bar: Bar):
self.sma.add(bar.close)
self.sma_slow.add(bar.close)
await self.trade_logic()
async def on_tick(self, bar: Bar):
pass
async def trade_logic(self):
if len(self.sma_slow) < 2 or self.sma_slow[-2] is None:
return
close = self.get("BTC/USDT", "5m").close
buy = self.sma[-2] < self.sma_slow[-2] and self.sma[-1] > self.sma_slow[-1]
sell = self.sma[-2] > self.sma_slow[-2] and self.sma[-1] < self.sma_slow[-1]
if buy:
await self.open("BTC/USDT", PositionType.LONG, 0.1, OrderType.LIMIT, close)
if sell:
await self.close("BTC/USDT", PositionType.LONG, 0.1, OrderType.LIMIT, close)