Bot Class System
The Bot class is the foundation of the trading bot system. All bots inherit from it and implement trading strategies.
Implementation Approaches
1a. Simple (Recommended): Single-ticker decisionFunction(row)
When to use: Your strategy can be expressed as logic on a single data row with technical indicators, for one symbol.
How it works:
- Base class fetches data for self.symbol (or self.tickers for multi-asset bots)
- Applies your function to each row
- Averages the last N decisions
- Executes trades automatically
- Fully backtestable via local_backtest() / local_optimize()
Example:
class MyBot(Bot):
def __init__(self):
super().__init__("MyBot", symbol="QQQ", interval="1d", period="1y")
def decisionFunction(self, row):
if row["momentum_rsi"] < 30:
return 1 # Buy
elif row["momentum_rsi"] > 70:
return -1 # Sell
return 0 # Hold
1b. Multi-ticker decisionFunction(row) — equal-weight
When to use: Same row-by-row logic applied across a basket of tickers with equal-weight sizing.
How it works:
- Pass tickers=["SPY", "QQQ", "GLD"] to __init__ instead of symbol=
- decisionFunction is called once per ticker per bar (unchanged signature)
- Buy signal: top up that ticker toward total_value / N
- Sell signal: liquidate that ticker's position
- Live trading: makeOneIteration() routes to _run_multi_ticker_iteration() automatically
- Backtesting: backtest_bot() inner-joins all ticker DataFrames on timestamp and simulates equal-weight
Example:
class MyMultiBot(Bot):
def __init__(self):
super().__init__("MyMultiBot", tickers=["SPY", "QQQ", "GLD"],
interval="1d", period="1y")
def decisionFunction(self, row):
if row["momentum_rsi"] < 30:
return 1
elif row["momentum_rsi"] > 70:
return -1
return 0
2. Medium Complexity: Override makeOneIteration()
When to use: - External APIs (e.g., Fear & Greed Index) - Custom data processing - Different timeframe handling
Example: See feargreedbot.py
3. Complex: Portfolio Optimization
When to use: - Multi-asset strategies - Portfolio rebalancing - Complex optimization algorithms
Example: See sharpeportfoliooptweekly.py
Bot Lifecycle
1. Bot.__init__(name, symbol, interval="1m", period="1d")
├── Creates/retrieves bot from database
├── Initializes portfolio with {"USD": 10000} if new
├── Sets up symbol and data cache
└── Stores interval and period for data fetching
2. Bot.run()
├── Calls makeOneIteration()
├── Executes buy/sell based on decision
└── Logs result to database (RunLog)
3. Bot.makeOneIteration() [default implementation]
├── Fetches data: getYFDataWithTA(saveToDB=True, ...)
├── Gets decision: getLatestDecision(data)
└── Executes trade if decision != 0
Key Methods
Data Fetching
# Raw market data
data = bot.getYFData(interval="1m", period="1d", saveToDB=True)
# With technical indicators
data = bot.getYFDataWithTA(interval="1m", period="1d", saveToDB=True)
Trading Operations
# Buy with all cash
bot.buy(symbol="QQQ")
# Buy specific amount
bot.buy(symbol="QQQ", quantityUSD=1000)
# Sell all holdings
bot.sell(symbol="QQQ")
# Rebalance portfolio
bot.rebalancePortfolio({"QQQ": 0.8, "GLD": 0.1, "USD": 0.1})
Portfolio Access
Data Caching
- Instance cache:
self.datacaches last fetched DataFrame (for single-ticker). For multi-ticker bots,self.datasis a dictionary caching DataFrames keyed by ticker. - Database persistence: Set
saveToDB=Truefor cross-run data reuse - Automatic freshness check: Stale data (>10 minutes) is refetched
Next Steps
- Bot API Reference - Complete method documentation
- Creating a Bot - Step-by-step guide