Rajandran R Creator of OpenAlgo - OpenSource Algo Trading framework for Indian Traders. Telecom Engineer turned Full-time Derivative Trader. Mostly Trading Nifty, Banknifty, High Liquid Stock Derivatives. Trading the Markets Since 2006 onwards. Using Market Profile and Orderflow for more than a decade. Designed and published 100+ open source trading systems on various trading tools. Strongly believe that market understanding and robust trading frameworks are the key to the trading success. Building Algo Platforms, Writing about Markets, Trading System Design, Market Sentiment, Trading Softwares & Trading Nuances since 2007 onwards. Author of Marketcalls.in

VectorBT Streamlit Backtesting App – Python Tutorial

4 min read

This Streamlit application is designed for backtesting trading strategies using the VectorBT library in Python. It provides a user-friendly interface to input various parameters for the trading strategy, such as symbols, dates, EMA periods, and more. Users can perform backtests and view detailed results including backtesting statistics, trades list, equity curve, drawdown, and portfolio plots.

Features

  • Interactive interface for strategy parameter input.
  • Integration with VectorBT for sophisticated backtesting.
  • Visualizations for equity curve, drawdown, and overall portfolio performance.

Requirements

To run this app locally, you need the following:

  • Python 3.x
  • Streamlit
  • vectorbt
  • pandas
  • numpy
  • plotly
  • pytz

Access the VectorBT Streamlit Cloud App

Explore the app directly: VectorBT Streamlit App.

Download the GitHub Code

Get the source code here: VectorBT-Streamlit GitHub Repository.

What is Streamlit?

Streamlit is an open-source Python library that turns data scripts into shareable web apps in minutes. It’s designed for users who need to rapidly prototype and deploy data applications. The beauty of Streamlit lies in its simplicity and interactivity, making it an ideal tool for building trading dashboards and applications.

VectorBT: A Powerful Tool for Traders

VectorBT (Vector BackTesting) is an analytics engine for Python used in trading strategies backtesting. It’s built on top of pandas, NumPy, and Plotly and integrates seamlessly with Streamlit to visualize trading strategies and metrics.

Installation and Setup Guidelines

Installation and Setup

Clone the repository:

git clone https://github.com/marketcalls/VectorBT-Streamlit/

Navigate to the app’s directory:

cd .\VectorBT-Streamlit\

Install required libraries:

pip install -r requirements.txt

To run the app, execute the following command in the terminal:

streamlit run app.py

VectorBT Streamlit Python Code

import streamlit as st
import vectorbt as vbt
import pandas as pd
import numpy as np
import plotly.graph_objs as go
from datetime import datetime
import pytz  # Make sure pytz is installed

# Convert date to datetime with timezone
def convert_to_timezone_aware(date_obj):
    return datetime.combine(date_obj, datetime.min.time()).replace(tzinfo=pytz.UTC)

# Streamlit interface

st.set_page_config(page_title='VectorBT Backtesting', layout='wide')
st.title("VectorBT Backtesting - www.marketcalls.in")

# Sidebar for inputs
with st.sidebar:
    # Inputs for the symbol, start and end dates
    st.header("Strategy Controls")
    
    # Inputs for the symbol, start and end dates
    symbol = st.text_input("Enter the symbol (e.g., 'AAPL')", value="HDFCBANK.NS")
    start_date = st.date_input("Start Date", value=pd.to_datetime("2010-01-01"))
    end_date = st.date_input("End Date", value=pd.to_datetime("2023-01-01"))

    # EMA controls
    short_ema_period = st.number_input("Short EMA Period", value=10, min_value=1)
    long_ema_period = st.number_input("Long EMA Period", value=20, min_value=1)
    
    st.header("Backtesting Controls")

    # Backtesting controls
    initial_equity = st.number_input("Initial Equity", value=100000)
    size = st.text_input("Position Size", value='50')  # Text input for size
    size_type = st.selectbox("Size Type", ["amount", "value", "percent"], index=2)  # Dropdown for size type
    fees = st.number_input("Fees (as %)", value=0.12, format="%.4f")
    direction = st.selectbox("Direction", ["longonly", "shortonly", "both"], index=0)

    # Button to perform backtesting
    backtest_clicked = st.button("Backtest")

# Main area for results
if backtest_clicked:
    start_date_tz = convert_to_timezone_aware(start_date)
    end_date_tz = convert_to_timezone_aware(end_date)

    # Fetch data
    data = vbt.YFData.download(symbol, start=start_date_tz, end=end_date_tz).get('Close')

    # Calculate EMAs and signals
    short_ema = vbt.MA.run(data, short_ema_period, short_name='fast', ewm=True)
    long_ema = vbt.MA.run(data, long_ema_period, short_name='slow', ewm=True)
    entries = short_ema.ma_crossed_above(long_ema)
    exits = short_ema.ma_crossed_below(long_ema)

    # Convert size to appropriate type
    if size_type == 'percent':
        size_value = float(size) / 100.0
    else:
        size_value = float(size)

    # Run portfolio
    portfolio = vbt.Portfolio.from_signals(
        data, entries, exits,
        direction=direction,
        size=size_value,
        size_type=size_type,
        fees=fees/100,
        init_cash=initial_equity,
        freq='1D',
        min_size =1,
        size_granularity = 1
    )

    # Create tabs
    tab1, tab2, tab3, tab4, tab5 = st.tabs(["Backtesting Stats", "List of Trades", 
                                          "Equity Curve", "Drawdown", "Portfolio Plot"])


    with tab1:
        # Display results
        st.markdown("**Backtesting Stats:**")
        stats_df = pd.DataFrame(portfolio.stats(), columns=['Value'])
        stats_df.index.name = 'Metric'  # Set the index name to 'Metric' to serve as the header
        st.dataframe(stats_df, height=800)  # Adjust the height as needed to remove the scrollbar

    with tab2:
        st.markdown("**List of Trades:**")
        trades_df = portfolio.trades.records_readable
        trades_df = trades_df.round(2)  # Rounding the values for better readability
        trades_df.index.name = 'Trade No'  # Set the index name to 'Trade Name' to serve as the header
        trades_df.drop(trades_df.columns[[0,1]], axis=1, inplace=True)
        st.dataframe(trades_df, width=800,height=600)  # Set index to False and use full width


    # Plotting
    equity_data = portfolio.value()
    drawdown_data = portfolio.drawdown() * 100

    with tab3:
    # Equity Curve
        equity_trace = go.Scatter(x=equity_data.index, y=equity_data, mode='lines', name='Equity',line=dict(color='green') )
        equity_fig = go.Figure(data=[equity_trace])
        equity_fig.update_layout(title='Equity Curve', xaxis_title='Date', yaxis_title='Equity',
                                 width=800,height=600)
        st.plotly_chart(equity_fig)

    with tab4:
        # Drawdown Curve
        drawdown_trace = go.Scatter(
            x=drawdown_data.index,
            y=drawdown_data,
            mode='lines',
            name='Drawdown',
            fill='tozeroy',
            line=dict(color='red')  # Set the line color to red
        )
        drawdown_fig = go.Figure(data=[drawdown_trace])
        drawdown_fig.update_layout(
            title='Drawdown Curve',
            xaxis_title='Date',
            yaxis_title='% Drawdown',
            template='plotly_white',
            width = 800,
            height = 600
        )
        st.plotly_chart(drawdown_fig)

    with tab5:
        # Portfolio Plot
        st.markdown("**Portfolio Plot:**")
        st.plotly_chart(portfolio.plot())

Step-by-Step Tutorial: Building a Trading Dashboard with VectorBT and Streamlit

Let’s dive into creating a simple yet effective trading dashboard using the provided Python code.

Step 1: Setting Up the Streamlit Interface

The Streamlit interface is initiated with st.set_page_config() to configure page properties. The title is set using st.title().

Step 2: Creating Sidebar for User Inputs

The sidebar (st.sidebar) is crucial for user interaction. It includes inputs for symbols, date range, EMA (Exponential Moving Average) periods, backtesting controls like initial equity, position size, fees, and the direction of trades. A button (st.button) triggers the backtesting.

Step 3: Backtesting Logic

Upon clicking the backtest button, the app:

  1. Converts user-input dates to timezone-aware datetime objects.
  2. Fetches the stock data using vbt.YFData.download().
  3. Computes short and long EMAs and generates entry and exit signals.
  4. Processes the position size based on user input.
  5. Executes the backtesting using vbt.Portfolio.from_signals().

Step 4: Displaying Results

The results are displayed in multiple tabs:

  1. Backtesting Stats: Summarizes the performance metrics of the strategy.
  2. List of Trades: Shows a detailed list of trades executed during the backtesting period.
  3. Equity Curve: Plots the equity curve of the portfolio over time.
  4. Drawdown: Visualizes the drawdown percentage, highlighting periods of loss.
  5. Portfolio Plot: A comprehensive plot of the portfolio’s performance.

Step 5: Visualization with Plotly

The dashboard leverages Plotly for visualizing the equity and drawdown curves. These interactive plots enhance the user experience, providing a clear and dynamic visual representation of the strategy’s performance.

Conclusion

Streamlit, combined with VectorBT, offers a powerful and user-friendly platform for traders and Python enthusiasts to backtest and visualize their trading strategies. By following this tutorial, you can build and customize your own trading dashboard, harnessing the power of Python and modern web technologies.

Further Exploration

I encourage you to modify and enhance the dashboard based on your trading preferences and strategies. Experiment with different indicators, assets, and backtesting parameters to fully explore the capabilities of VectorBT and Streamlit.

Rajandran R Creator of OpenAlgo - OpenSource Algo Trading framework for Indian Traders. Telecom Engineer turned Full-time Derivative Trader. Mostly Trading Nifty, Banknifty, High Liquid Stock Derivatives. Trading the Markets Since 2006 onwards. Using Market Profile and Orderflow for more than a decade. Designed and published 100+ open source trading systems on various trading tools. Strongly believe that market understanding and robust trading frameworks are the key to the trading success. Building Algo Platforms, Writing about Markets, Trading System Design, Market Sentiment, Trading Softwares & Trading Nuances since 2007 onwards. Author of Marketcalls.in

[Live Coding Webinar] Build Your First Trading Bridge for…

In this course, you will be learning to build your own trading bridge using Python. This 60-minute session is perfect for traders, Python enthusiasts,...
Rajandran R
1 min read

How to Place Orders Concurrently using ThreadPoolExecutor – Python…

Creating concurrent orders is essential for active traders, especially those handling large funds, as it allows for executing multiple trade orders simultaneously, thereby maximizing...
Rajandran R
2 min read

Host your Python Flask Web Application using pyngrok and…

Ngrok offers several significant advantages for developers, especially when it comes to testing applications or hosting machine learning models. Ngrok allows you to expose...
Rajandran R
1 min read

Leave a Reply

Get Notifications, Alerts on Market Updates, Trading Tools, Automation & More