To create a custom trading strategy, inherit from AbstractStrategy. You must implement the init method for setup and the handle method to process incoming market data (quote).
Key Components:
init(self, ...): Initialize strategy parameters, state variables (like counters or signal flags), and set the Portfolio.initial_balance.handle(self, quote): This method is called for every new quote. Use the quote object to access market data (e.g., quote.open, quote.close, quote.time, quote.symbol).Order: Use Order.open(**props) to open a new position and Order.close(position, ...) to close an existing one.Portfolio: Access global portfolio settings like Portfolio.initial_balance.
Example: Three-bar strategy
This strategy enters a position after a specific sequence of bullish or bearish bars.
from quantdom import AbstractStrategy, Order, Portfolio
class ThreeBarStrategy(AbstractStrategy):
def init(self, high_bars=3, low_bars=3):
Portfolio.initial_balance = 100000 # default value
self.seq_low_bars = 0
self.seq_high_bars = 0
self.signal = None
self.last_position = None
self.volume = 100 # shares
self.high_bars = high_bars
self.low_bars = low_bars
def handle(self, quote):
if self.signal:
props = {
'symbol': self.symbol, # current selected symbol
'otype': self.signal,
'price': quote.open,
'volume': self.volume,
'time': quote.time,
}
if not self.last_position:
self.last_position = Order.open(**kwargs)
elif self.last_position.type != self.signal:
Order.close(self.last_position, price=quote.open, time=quote.time)
self.last_position = Order.open(**props)
self.signal = False
self.seq_high_bars = self.seq_low_bars = 0
if quote.close > quote.open:
self.seq_high_bars += 1
self.seq_low_bars = 0
else:
self.seq_high_bars = 0
self.seq_low_bars += 1
if self.seq_high_bars == self.high_bars:
self.signal = Order.BUY
elif self.seq_low_bars == self.low_bars:
self.signal = Order.SELL
from quantdom import AbstractStrategy, Order, Portfolio
class ThreeBarStrategy(AbstractStrategy):
def init(self, high_bars=3, low_bars=3):
Portfolio.initial_balance = 100000 # default value
self.seq_low_bars = 0
self.seq_high_bars = 0
self.signal = None
self.last_position = None
self.volume = 100 # shares
self.high_bars = high_bars
self.low_bars = low_bars
def handle(self, quote):
if self.signal:
props = {
'symbol': self.symbol, # current selected symbol
'otype': self.signal,
'price': quote.open,
'volume': self.volume,
'time': quote.time,
}
if not self.last_position:
self.last_position = Order.open(**props)
elif self.last_position.type != self.signal:
Order.close(self.last_position, price=quote.open, time=quote.time)
self.last_position = Order.open(**props)
self.signal = False
self.seq_high_bars = self.seq_low_bars = 0
if quote.close > quote.open:
self.seq_high_bars += 1
self.seq_low_bars = 0
else:
self.seq_high_bars = 0
self.seq_low_bars += 1
if self.seq_high_bars == self.high_bars:
self.signal = Order.BUY
elif self.seq_low_bars == self.low_bars:
self.signal = Order.SELL