Leveraged Futures Exchange for Simulated Trading (LFEST)

:warning: This is a personal project, use a your own risk.

:warning: The results may not represent real trading results on any given exchange.

This crate aims to be a high performance simulated exchange capable of leveraged positions.

Order Types

The supported order types are: - market, - limit - stop_market

Performance Metrics:

The following performance metrics are available through AccTracker struct: - totalrpnl - sharpe - sharpedailyreturns - sortino - cumulative fees - sharpesterlingratio - maxdrawdown - maxupnldrawdown - numtrades - tradepercentage - buyratio - winratio - turnover - limitorderfillratio - limitordercancellationratio

How to use

To use this crate in your project, add the following to your Cargo.toml: [dependencies] lfest = { git = "https://github.com/MathisWellmann/lfest-rs" }

Then proceed to use it in your code. The following example uses a Trade to update the bid and ask price of the exchange.

```rust mod load_trades;

use lfest::{Config, Exchange, Order, Side}; use loadtrades::loadtradesfromcsv; use rand::{thread_rng, Rng}; use std::time::Instant;

fn main() { let t0 = Instant::now();

let config = Config{
    fee_maker: -0.00025,
    fee_taker: 0.001,
    starting_balance_base: 1.0,
    use_candles: false,
    leverage: 1.0
};
let mut exchange = Exchange::new(config);

// load trades from csv file
let trades = load_trades_from_csv("./data/Bitmex_XBTUSD_1M.csv").unwrap();

// use random action to buy or sell
let mut rng = thread_rng();

for t in &trades {
    let liq = exchange.consume_trade(t);
    if liq {
        println!(
            "position liquidated, \
        but there could still be enough wallet_balance to open a new position"
        );
    }

    // randomly buy or sell using a market order
    let r = rng.gen::<f64>();
    // Trade a fraction of the available wallet balance
    let order_size: f64 = exchange.margin().wallet_balance() * 0.01;
    let order: Order = if r > 0.98 {
        // Sell order
        Order::market(Side::Sell, order_size)
    } else if r < 0.02 {
        // BUY
        Order::market(Side::Buy, order_size)
    } else {
        // Neutral
        continue;
    };
    let _order_err = exchange.submit_order(order);
    // Handle order error here if needed
}
println!(
    "time to simulate 1 million historical trades and {} orders: {}ms",
    exchange.acc_tracker().num_trades(),
    t0.elapsed().as_millis()
);
analyze_results(&exchange);

}

/// analyzer the resulting performance metrics of the traded orders fn analyzeresults(e: &Exchange) { let rpnl = e.acctracker().totalrpnl(); let sharpe = e.acctracker().sharpe(); let sortino = e.acctracker().sortino(); let sterlingratio = e.acctracker().sharpesterlingratio(); let maxdrawdown = e.acctracker().maxdrawdown(); let maxupnldrawdown = e.acctracker().maxupnldrawdown(); let numtrades = e.acctracker().numtrades(); let buyratio = e.acctracker().buyratio(); let turnover = e.acctracker().turnover(); let winratio = e.acctracker().winratio(); println!( "rpnl: {:.2}, sharpe: {:.2}, sortino: {:.2}, sr: {:.2}, \ dd: {:.2}, upnldd: {:.2}, #trades: {}, buyratio: {:.2}, turnover: {}, winratio: {}", rpnl, sharpe, sortino, sterlingratio, maxdrawdown, maxupnldrawdown, numtrades, buyratio, turnover, win_ratio ); }

``` See the examples folder for more code.

Benchmark

See the example use_trades.rs and compile in release mode to see that the Exchange is capable of simulating 1 million historical trades and executing ~40k market orders in ~470ms.

Dependencies

A non trivial dependency is trade_aggregation as the exchange relies on the Trade and Candle struct.

Contributions

If you find a bug or would like to help out, feel free to create a pull-request.

Donations :moneybag: :moneywithwings:

I you would like to support the development of this crate, feel free to send over a donation:

Monero (XMR) address: plain 47xMvxNKsCKMt2owkDuN1Bci2KMiqGrAFCQFSLijWLs49ua67222Wu3LZryyopDVPYgYmAnYkSZSz9ZW2buaDwdyKTWGwwb

monero

License

Copyright (C) 2020

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License along with this program. If not, see https://www.gnu.org/licenses/.

GNU AGPLv3