#trading #backtesting #crypto #stocks #investment

barter

Framework for building event-driven live-trading & backtesting engines

29 releases (5 breaking)

new 0.6.2 Nov 27, 2021
0.6.1 Nov 27, 2021
0.5.10 Nov 26, 2021
0.4.1 Nov 15, 2021
0.1.0 Mar 27, 2021

#9 in Simulation

Download history 28/week @ 2021-08-10 1/week @ 2021-08-17 3/week @ 2021-09-14 3/week @ 2021-09-21 15/week @ 2021-09-28 14/week @ 2021-10-05 13/week @ 2021-10-12 15/week @ 2021-10-19 24/week @ 2021-11-09 231/week @ 2021-11-16 81/week @ 2021-11-23

336 downloads per month

MIT license

315KB
7K SLoC

Barter

Barter is an open-source Rust framework for building event-driven live-trading & backtesting systems. Algorithmic trade with the peace of mind that comes from knowing your strategies have been backtested with a near-identical trading Engine. It is:

  • Fast: Barter provides a multi-threaded trading Engine framework built in high-performance Rust (in-rust-we-trust).
  • Easy: Barter provides a modularised data architecture that focuses on simplicity.
  • Customisable: A set of traits define how every Barter component communicates, providing a highly extensible framework for trading.

Crates.io MIT licensed Build Status Discord chat

API Documentation | Chat

Overview

Barter is an open-source Rust framework for building event-driven live-trading & backtesting systems. It provides a high-performance, easy to customise, trading Engine that enables backtesting strategies on a near-identical system to live trading. At a high level, it provides several de-coupled components that interact via a set of traits:

  • Data: Continuer & MarketGenerator traits govern the generation of a MarketEvents data feed that acts as the system heartbeat. For example, a LiveCandleHandler implementation is provided utilising Barter-Data's WebSocket functionality to provide a live market Candle data feed to the system.
  • Strategy: The SignalGenerator trait governs potential generation of SignalEvents after analysing incoming MarketEvents. SignalEvents are advisory signals sent to the Portfolio for analysis.
  • Portfolio: MarketUpdater, OrderGenerator, and FillUpdater govern global state Portfolio implementations. A Portfolio may generate OrderEvents after receiving advisory SignalEvents from a Strategy. The Portfolio's state updates after receiving MarketEvents and FillEvents.
  • Execution: The FillGenerator trait governs the generation of FillEvents after receiving OrderEvents from the Portfolio. For example, a SimulatedExecution handler implementation is provided for simulating any exchange execution behaviour required in dry-trading or backtesting runs.
  • Statistic: Provides metrics such as Sharpe Ratio, Calmar Ratio, and Max Drawdown to analyse trading session performance. One-pass dispersion algorithms analyse each closed Position and efficiently calculates a trading summary.
  • Trader: Capable of trading a single market pair using a customisable selection of it's own Data, Strategy & Execution instances, as well as shared access to a global Portfolio.
  • Engine: Multi-threaded trading Engine capable of trading with an arbitrary number of Trader market pairs. Each contained Trader instance operates on its own thread.

Example

  • For brevity: Imports are not included.
  • For simplicity:
    • Engine and Trader(s) are configuration with hard-coded values rather than loaded in configuration values.
    • Remote shutdown is not orchestrated via the engine_termination_rx, this should be added as per your taste (eg/ HTTP endpoint).
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Setup Logger & Load Config For Engine & Trader Instances Here

    // Create termination channels
    let (engine_termination_tx, engine_termination_rx) = oneshot::channel();    // Engine graceful remote shutdown
    let (traders_termination_tx, _) = broadcast::channel(1);                    // Shutdown channel to broadcast remote shutdown to every Trader instance
    
    // Create EventSink channel to listen to all Engine Events in real-time
    let (event_tx, event_rx) = unbounded_channel();
    let event_sink = EventSink::new();

    // Build global shared-state MetaPortfolio
    let portfolio = Arc::new(Mutex::new(
        MetaPortfolio::builder()
            .id(Uuid::new_v4())
            .starting_cash(10_000.0)
            .repository(InMemoryRepository::new())
            .allocation_manager(DefaultAllocator { default_order_value: 100.0 })
            .risk_manager(DefaultRisk {})
            .build_and_init()
            .expect("failed to build & initialise MetaPortfolio"),
    ));
    
    // Build Trader(s)
    let mut traders = Vec::new();
    traders.push(
        Trader::builder()
            .termination_rx(traders_termination_tx.subscribe())
            .event_sink(event_sink.clone())
            .portfolio(Arc::clone(&portfolio))
            .data(HistoricCandleHandler::new(HistoricDataLego { 
                exchange: "Binance".to_string(),
                symbol: "btcusdt".to_string(),
                candle_iterator: vec![Candle::default()].into_iter(),
            })
            .strategy(RSIStrategy::new(StrategyConfig { rsi_period: 14 }))
            .execution(SimulatedExecution::new(ExecutionConfig {
                simulates_fees_pct: Fees {
                    exchange: 0.1,
                    slippage: 0.05,
                    network: 0.0,}
            }))
            .build()
            .expect("failed to build trader")
    );
    
    // Build Engine
    let engine = Engine::builder()
        .termination_rx(engine_termination_rx)
        .traders_termination_tx(traders_termination_tx)
        .statistics(TradingSummary::new(&config.statistics))
        .portfolio(portfolio)
        .traders(traders)
        .build()
        .expect("failed to build engine");
        
    // Listen to Engine Events & do something with them
    tokio::spawn(listen_to_events(event_rx));
        
    // --- Run Trading Session Until Remote Shutdown ---
    engine.run().await;
}

Getting Help

Firstly, see if the answer to your question can be found in the API Documentation. If the answer is not there, I'd be happy to help to Chat and try answer your question via Discord.

Contributing

🎉 Thanks for your help in improving the barter ecosystem! Please do get in touch on the discord to discuss development, new features, and the future roadmap.

Related Projects

In addition to the Barter crate, the Barter project also maintains:

  • Barter-Data: High performance & normalised WebSocket intergration for leading cryptocurrency exchanges - batteries included.

Roadmap

  • Build & integrate the new "Barter-Execution" library to provide additional out-of-the-box functionality for executing OrderEvents.
  • Build Strategy utilities for aggregating tick-by-tick Trades and/or Candles into multi-timeframe datastructures, as well as providing an example multi-timeframe Strategy using the utilities.
  • Flesh out the MetaPortfolio Allocator & Risk management systems.
  • And more!

Licence

This project is licensed under the MIT license.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Tokio by you, shall be licensed as MIT, without any additional terms or conditions.

Dependencies

~24MB
~525K SLoC