GlowBack allows you to create custom trading strategies by implementing Python classes with specific callback methods. Strategies receive market data events and can execute trades through a portfolio interface.
class MyStrategy: def __init__(self): self.name = "My Strategy" # Initialize strategy state pass def on_bar(self, bar, portfolio): """Called for each new bar of market data Args: bar: Bar object with OHLCV data portfolio: Portfolio object for executing trades Returns: Optional list of log messages """ # Strategy logic here return [] # Optional: return log messages
def on_bar(self, bar, portfolio): position = portfolio.get_position(bar.symbol.symbol) if position > 0: return [f"Currently holding {position} shares"] else: return [f"No position in {bar.symbol.symbol}"]
class SMAStrategy: def __init__(self, short_window=20, long_window=50): self.name = "SMA Crossover Strategy" self.short_window = short_window self.long_window = long_window self.prices = {} self.position = {} def on_bar(self, bar, portfolio): symbol = bar.symbol.symbol # Track price history if symbol not in self.prices: self.prices[symbol] = [] self.prices[symbol].append(bar.close) # Need enough history if len(self.prices[symbol]) < self.long_window: return [] # Calculate moving averages prices = self.prices[symbol] short_ma = sum(prices[-self.short_window:]) / self.short_window long_ma = sum(prices[-self.long_window:]) / self.long_window logs = [] position = portfolio.get_position(symbol) # Buy signal: short MA crosses above long MA if short_ma > long_ma and position == 0: shares = int(portfolio.cash * 0.95 / bar.close) if shares > 0: portfolio.buy(symbol, shares, bar.close, bar.timestamp) logs.append(f"BUY: {shares} shares at ${bar.close:.2f}") logs.append(f" Short MA: {short_ma:.2f}, Long MA: {long_ma:.2f}") # Sell signal: short MA crosses below long MA elif short_ma < long_ma and position > 0: portfolio.sell(symbol, position, bar.close, bar.timestamp) logs.append(f"SELL: {position} shares at ${bar.close:.2f}") logs.append(f" Short MA: {short_ma:.2f}, Long MA: {long_ma:.2f}") return logs
To use a custom strategy, pass it to a backtest framework:
# For Streamlit UI or custom backtest runnerstrategy_code = '''class MyStrategy: def __init__(self): self.name = "My Custom Strategy" def on_bar(self, bar, portfolio): # Your strategy logic return []'''# In your backtest runnernamespace = {}exec(strategy_code, namespace)# Find and instantiate strategystrategy_classes = [obj for obj in namespace.values() if isinstance(obj, type) and hasattr(obj, 'on_bar')]strategy = strategy_classes[0]()# Run backtest (implementation specific)# ...
The current Python API uses a simplified portfolio interface. For production Rust-backed strategies with full event-driven execution, see the Rust Strategy API.
class EfficientStrategy: def __init__(self): self.prices = {} # Use dicts for multi-symbol tracking self.indicators = {} def on_bar(self, bar, portfolio): symbol = bar.symbol.symbol # Initialize symbol-specific state if symbol not in self.prices: self.prices[symbol] = [] self.indicators[symbol] = {}
def on_bar(self, bar, portfolio): symbol = bar.symbol.symbol if len(self.prices[symbol]) < self.required_history: return [] # Skip trading until enough data # Proceed with strategy logic