Warning
DISCLAIMER: This software is for educational and research purposes only. Trading involves significant risk of loss and is not suitable for all investors. Use of this framework (including "Step 5: Run Your Bot Live") is strictly at your own risk. The authors and contributors are not liable for any financial losses, damages, or unintended trades incurred. Always test strategies thoroughly in a paper-trading environment before deploying real capital.
Get your first trading bot up and running locally in minutes. This guide covers local development, testing, and running bots live.
- Python 3.12+
- Docker (for local PostgreSQL)
The trading bot system requires a PostgreSQL database to store bot state, trades, and historical data.
Start a PostgreSQL container:
docker run -d --name postgres-tradingbot \
-e POSTGRES_PASSWORD=yourpassword \
-e POSTGRES_DB=tradingbot \
-p 5432:5432 \
postgres:17-alpineConfigure the database connection:
export POSTGRES_URI="postgresql://postgres:yourpassword@localhost:5432/tradingbot"Note: For production deployment, see the Deployment Guide for Kubernetes/Helm setup.
Install project dependencies using uv:
uv syncThe trading bot framework supports three abstraction levels, depending on your strategy complexity.
For strategies that can be expressed as logic on a single data row with technical indicators.
How it works: The base class fetches data, applies your function to each row, averages the decisions, and executes trades automatically.
Example:
from tradingbot.utils.botclass import Bot
class MyBot(Bot):
def __init__(self):
super().__init__("MyBot", "QQQ", interval="1m", period="1d")
def decisionFunction(self, row):
"""
Trading decision based on technical indicators.
Returns:
-1: Sell signal
0: Hold (no action)
1: Buy signal
"""
# Access 150+ technical indicators via row["indicator_name"]
if row["momentum_rsi"] < 30:
return 1 # Buy - oversold
elif row["momentum_rsi"] > 70:
return -1 # Sell - overbought
return 0 # HoldAvailable Indicators: After calling getYFDataWithTA(), you have access to ~150+ indicators:
- Momentum:
momentum_rsi,momentum_stoch,momentum_roc, etc. - Trend:
trend_macd,trend_adx,trend_sma_fast, etc. - Volatility:
volatility_bbh,volatility_bbl,volatility_atr, etc. - Volume:
volume_obv,volume_mfi,volume_vwap, etc.
See Technical Analysis Guide for the complete list.
For bots that need external APIs, custom data processing, or different timeframe handling.
Example (using external Fear & Greed Index API):
import fear_and_greed
from tradingbot.utils.botclass import Bot
class FearGreedBot(Bot):
def __init__(self):
super().__init__("FearGreedBot", "QQQ")
def makeOneIteration(self):
"""
Custom iteration logic with external API.
Returns:
-1: Sell signal
0: Hold
1: Buy signal
"""
# Fetch external data
fear_greed_index = fear_and_greed.get().value
cash = self.dbBot.portfolio.get("USD", 0)
holding = self.dbBot.portfolio.get("QQQ", 0)
if fear_greed_index >= 70 and cash > 0:
self.buy("QQQ") # Extreme greed - buy
return 1
elif fear_greed_index <= 30 and holding > 0:
self.sell("QQQ") # Extreme fear - sell
return -1
return 0 # HoldFor multi-asset strategies, portfolio rebalancing, or complex optimization algorithms.
Example (Sharpe ratio portfolio optimization):
from pypfopt import EfficientFrontier, expected_returns, risk_models
from tradingbot.utils.botclass import Bot
class PortfolioBot(Bot):
def __init__(self):
super().__init__(
"PortfolioBot",
tickers=["QQQ", "GLD", "TLT", "AAPL"],
interval="1d",
period="3mo"
)
def makeOneIteration(self):
"""
Rebalance portfolio using optimization.
Returns:
0: Rebalancing completed
"""
# Fetch data for multiple symbols
data = self.getYFDataMultiple(
self.tickers,
interval="1d",
period="3mo",
saveToDB=True
)
# Convert to wide format for optimization
df = self.convertToWideFormat(data, value_column="close")
# Calculate optimal weights
mu = expected_returns.mean_historical_return(df)
S = risk_models.sample_cov(df)
ef = EfficientFrontier(mu, S)
ef.max_sharpe()
weights = ef.clean_weights()
# Rebalance portfolio
self.rebalancePortfolio(weights)
return 0Before running your bot live, test and optimize it locally.
Test your bot's performance on historical data:
from tradingbot.utils.botclass import Bot
bot = MyBot()
# Run backtest with current parameters
results = bot.local_backtest(initial_capital=10000.0)
print(f"Yearly Return: {results['yearly_return']:.2%}")
print(f"Sharpe Ratio: {results['sharpe_ratio']:.2f}")
print(f"Max Drawdown: {results['maxdrawdown']:.2%}")
print(f"Number of Trades: {results['nrtrades']}")Optimize your bot's parameters automatically:
class MyBot(Bot):
# Define hyperparameter search space
param_grid = {
"rsi_buy": [65, 70, 75],
"rsi_sell": [25, 30, 35],
"adx_threshold": [15, 20, 25],
}
def __init__(self, rsi_buy=70.0, rsi_sell=30.0, adx_threshold=20.0, **kwargs):
super().__init__("MyBot", "QQQ", interval="1m", period="1d", **kwargs)
self.rsi_buy = rsi_buy
self.rsi_sell = rsi_sell
self.adx_threshold = adx_threshold
def decisionFunction(self, row):
if row["momentum_rsi"] < self.rsi_buy:
return 1
elif row["momentum_rsi"] > self.rsi_sell:
return -1
return 0
# Optimize and backtest
bot = MyBot()
bot.local_development()
# Prints best parameters in copy-paste format
# Then backtests with those parameters
# Copy the printed parameters into __init__ defaultsKey Features:
- Data pre-fetching: Historical data is fetched once and reused for all parameter combinations (dramatically faster)
- Database caching: Data is saved to DB on first fetch, subsequent runs reuse cached data
- Parallel execution: Uses multiple CPU cores by default
- Automatic period adjustment: For minute-level intervals, automatically uses 7 days instead of 1 year (respects Yahoo Finance limits)
Methods:
bot.local_development()- Full workflow: optimize + backtestbot.local_optimize()- Just optimize parametersbot.local_backtest()- Just backtest current parameters
Once you're satisfied with backtesting results, run your bot live:
from tradingbot.utils.botclass import Bot
bot = MyBot()
bot.run() # Executes one iteration, makes trades, logs to databaseWhat bot.run() does:
- Calls
makeOneIteration()(or uses default implementation withdecisionFunction()) - Executes buy/sell operations based on the decision
- Updates portfolio in the database
- Logs the result to
RunLogtable - Handles errors gracefully (logs to database before re-raising)
Complete Example:
from tradingbot.utils.botclass import Bot
class MyBot(Bot):
def __init__(self):
super().__init__("MyBot", "QQQ", interval="1m", period="1d")
def decisionFunction(self, row):
if row["momentum_rsi"] < 30:
return 1
elif row["momentum_rsi"] > 70:
return -1
return 0
if __name__ == "__main__":
bot = MyBot()
# Optional: Test locally first
# bot.local_backtest()
# bot.local_development() # If you have param_grid defined
# Run live
bot.run()Save this to tradingbot/mybot.py and run:
python tradingbot/mybot.py- Deployment: Learn how to deploy bots to Kubernetes with Helm in the Deployment Guide
- Creating Bots: See detailed bot creation patterns in Creating a Bot
- Architecture: Understand the Bot Class System
- API Reference: Explore the complete Bot API Reference
- Examples: Check out Example Bots for more inspiration