Quick Start
This guide shows the minimum to load data, create strategy, run backtesting, and inspect the results.
Install
pip install stocksimpy
Minimal working example (copy & run)
from stocksimpy import *
# Load ~1 year of data
data = StockData.from_yfinance(["AAPL"], days_before=365)
# Use a built-in fixed-size strategy (RSI momentum)
strategy = Strategy.rsi_momentum_fixed()
# Create a backtester instance
bt = Backtester(symbol="AAPL", data=data, strategy=strategy)
# Run the backtest (fixed-size strategies use run_backtest_fixed)
bt.run_backtest_fixed()
# Performance summary
perf = Performance(bt)
print(perf.generate_risk_report())
# Visualization
viz = Visualize(bt)
figure = viz.visualize_backtest()
figure.show()
This gives you real trades, P/L values, risk stats, and a basic equity curve in seconds.
Writing your own strategy
Stocksimpy supports two strategy styles
Fixed strategies (simplest)
Same trade size on every buy/sell
Strategy sees past data only
Must return one of: “buy”, “sell”, “hold”
Minimal custom fixed strategy example:
def sma_crossover_fixed(data):
close = data["Close"]
short = close.rolling(20).mean()
long = close.rolling(50).mean()
if short.iloc[-1] > long.iloc[-1]:
return "buy"
elif short.iloc[-1] < long.iloc[-1]:
return "sell"
else:
return "hold"
You can either calculate your own indicator results or use built-in functions to calculate them Here is an alternative to the previous code:
# This code adds the indicators
# Code this part before running your bactesting
data.add_indicator(calculate_sma, "close", 20)
data.add_indicator(calculate_sma, "close", 50)
# Then your strategy becomes
def sma_crossover_fixed(data):
if data["sma_20"].iloc[-1] > data["sma_50"].iloc[-1]:
return "buy"
elif data["sma_20"].iloc[-1] < data["sma_50"].iloc[-1]:
return "sell"
else:
return "hold"
Usage:
bt = Backtester("AAPL", data, sma_crossover_fixed)
bt.run_backtest_fixed()
Dynamic strategies (more control)
Trade size can change per trade
Strategy receives past data + current holdings
Must return (signal, trade_amount)
signal in “buy” | “sell” | “hold”
trade_amount is an integer (shares)
Minimal dynamic strategy example
Minimal custom dynamic strategy
# Add the following for built-in rsi calculation
data.add_indicator(calculate_rsi, "close", 14)
def rsi_dynamic(data, holdings):
latest = data["rsi_14"].iloc[-1]
if latest < 30:
return "buy", 10 # accumulate
elif latest > 70 and holdings > 0:
return "sell", holdings # exit position
else:
return "hold", 0
Usage:
bt = Backtester("AAPL", data, rsi_dynamic)
bt.run_backtest_dynamic()
Useful shortcuts
Built-in strategies live in Strategy
Built-in indicators live in Indicators
You can implement them directly through add_indicator() from StockData
Fixed: run_backtest_fixed()
Dynamic: run_backtest_dynamic()
Visuals: Visualize(bt).visualize_backtest()
Reports: Performance(bt).generate_risk_report()
When to use fixed vs dynamic
Feature |
Fixed |
Dynamic |
|---|---|---|
Trade size |
constant |
variable |
Access to current holdings |
no |
yes |
Return value |
“buy/sell/hold” |
(“buy/sell/hold”, amount) |
Best for |
simple rules |
scaling in/out, position sizing |
If you are unsure start with fixed.