Performance Metrics
Performance Metrics return a float and are not part of the DataFrame Extension. They are called the Standard way. The DataFrame must have a DatetimeIndex for time-based metrics such as cagr.
import pandas_ta_classic as ta
result = ta.cagr(df.close)
Available Metrics
Compounded Annual Growth Rate: cagr
Calmar Ratio: calmar_ratio
Downside Deviation: downside_deviation
Jensen’s Alpha: jensens_alpha
Log Max Drawdown: log_max_drawdown
Max Drawdown: max_drawdown
Pure Profit Score: pure_profit_score
Sharpe Ratio: sharpe_ratio
Sortino Ratio: sortino_ratio
Volatility: volatility
Backtesting
Pandas TA Classic provides trading signals and indicator output suitable for popular backtesting frameworks.
backtesting.py
For backtesting.py, use a bridge function to feed pandas-ta-classic indicator output into the backtester. See the integration tutorial for a full walkthrough and the runnable examples/backtesting_py_strategy.py script.
import pandas as pd
import pandas_ta_classic as ta
from backtesting import Backtest, Strategy
from backtesting.test import GOOG
from backtesting.lib import crossover
def ta_bridge(data, indicator_fn):
df = pd.DataFrame({
'Open': data.Open, 'High': data.High,
'Low': data.Low, 'Close': data.Close,
'Volume': data.Volume,
})
result = indicator_fn(df)
if isinstance(result, pd.DataFrame):
return tuple(result[col].to_numpy() for col in result.columns)
return result.to_numpy()
class SMACrossover(Strategy):
fast_length = 10
slow_length = 20
def init(self):
self.sma_fast = self.I(
ta_bridge, self.data,
lambda df: df.ta.sma(length=self.fast_length),
)
self.sma_slow = self.I(
ta_bridge, self.data,
lambda df: df.ta.sma(length=self.slow_length),
)
def next(self):
if crossover(self.sma_fast, self.sma_slow):
if not self.position:
self.buy(size=0.1)
elif crossover(self.sma_slow, self.sma_fast):
if self.position:
self.position.close()
bt = Backtest(GOOG, SMACrossover, cash=10000, commission=0.002)
stats = bt.run()
print(stats)
backtrader
For backtrader, precompute indicators with pandas-ta-classic before
passing data to cerebro. Use a dynamic PandasData subclass to expose
extra columns as lines. See the integration tutorial and the runnable
examples/backtrader_strategy.py
script.
import pandas as pd
import pandas_ta_classic as ta
import backtrader as bt
def make_feed(df: pd.DataFrame, *extra_cols: str) -> type:
lines = tuple(extra_cols)
params = tuple((col, -1) for col in extra_cols)
return type('PandasDataWithTA', (bt.feeds.PandasData,), {'lines': lines, 'params': params})
df['sma_fast'] = ta.sma(df['Close'], length=10)
df['sma_slow'] = ta.sma(df['Close'], length=20)
df = df.dropna()
cerebro = bt.Cerebro()
cerebro.adddata(make_feed(df, 'sma_fast', 'sma_slow')(dataname=df))
cerebro.addstrategy(SMACrossover)
cerebro.broker.setcash(10_000.0)
results = cerebro.run()
vectorbt
Use ta.tsignals to generate entry/exit signals for vectorbt’s
Portfolio.from_signals method.
For a comprehensive example, see the Jupyter Notebook VectorBT Backtest with Pandas TA in the examples directory.
import pandas as pd
import pandas_ta_classic as ta
import vectorbt as vbt
df = pd.read_csv("your_data.csv")
df['sma_short'] = df.ta.sma(length=20)
df['sma_long'] = df.ta.sma(length=50)
entries = df['sma_short'] > df['sma_long']
exits = df['sma_short'] < df['sma_long']
signals = ta.tsignals(entries, asbool=True)
portfolio = vbt.Portfolio.from_signals(
df['close'],
entries=signals['TS_Entries'],
exits=signals['TS_Exits'],
)
portfolio.stats()