GithubHelp home page GithubHelp logo

mathiswellmann / trade_aggregation-rs Goto Github PK

View Code? Open in Web Editor NEW
55.0 2.0 18.0 5.13 MB

Aggregate trade data into user-defined candles using information driven rules

License: GNU Affero General Public License v3.0

Rust 98.26% Nix 1.74%
trading aggregation candles candlestick-chart volume trader trade-aggregation tick

trade_aggregation-rs's Introduction

Trade Aggregation

A high performance, modular and flexible trade aggregation crate, producing Candle data, suitable for low-latency applications and incremental updates. It allows the user to choose the rule dictating how a new candle is created through the AggregationRule trait, e.g: Time, Volume based or some other information driven rule. It also allows the user to choose which type of candle will be created from the aggregation process through the ModularCandle trait. Combined with the Candle macro, it enables the user to flexibly create any type of Candle as long as each component implements the CandleComponent trait. The aggregation process is also generic over the type of input trade data as long as it implements the TakerTrade trait, allowing for greater flexibility for downstream projects.

See MathisWellmann/go_trade_aggregation for a go implementation with less features and performance.

Here is a sample trade series of Bitmex_XBTUSD aggregated into 15 minute candles: time_candles

Features:

AggregationRule:

The pre-existing rules in this crate include:

'AggregationRule' Description
TimeRule Create candles every n seconds
AlignedTimeRule Same as TimeRule but candles are aligned to the start of a period
VolumeRule Create candles every n units traded
TickRule Create candles every n ticks
RelativePriceRule Create candles with every n basis points price movement (Renko)

If these don't satisfy your desires, just create your own by implementing the AggregationRule trait, and you can plug and play it into the GenericAggregator.

CandleComponent:

These pre-existing 'CandleComponents' exist out of the box:

'CandleComponent' Description
Open Price at the beginning of a candle
High Maximum price during the candle
Low Minimum price during the candle
Close Price at the end of a candle
Volume The cumulative trading volume
NumTrades The number of trades during the candle
AveragePrice The equally weighted average price
WeightedPrice The volume weighted price
StdDevPrices Keeps track of the standard deviation of prices
StdDevSizes Keeps track of the standard deviation of sizes
TimeVelocity Essentially how fast the candle was created time wise
Entropy Binary Shannon entropy using the trade side as inputs
Trades Just returns the observed trades during that candle

And again, if these don't satisfy your needs, just bring your own by implementing the CandleComponent trait and you can plug them into your own candle struct.

How to use:

To use this crate in your project, add the following to your Cargo.toml:

[dependencies]
trade_aggregation = "^9"

Lets aggregate all trades into time based 1 minute candles, consisting of open, high, low and close information. Notice how easy it is to specify the 'AggregationRule' and 'ModularCandle' being used in the process. One can easily plug in their own implementation of those trait for full customization. This examples uses an online style approach to update with each tick:

use trade_aggregation::{
    candle_components::{Close, High, Low, Open},
    *,
};

#[derive(Debug, Default, Clone, Candle)]
struct MyCandle {
    open: Open,
    high: High,
    low: Low,
    close: Close,
}

fn main() {
    let trades = load_trades_from_csv("data/Bitmex_XBTUSD_1M.csv")
        .expect("Could not load trades from file!");

    // specify the aggregation rule to be time based and the resolution each trade timestamp has
    let time_rule = TimeRule::new(M1, TimestampResolution::Millisecond);
    // Notice how the aggregator is generic over the output candle type, 
    // the aggregation rule as well as the input trade data
    let mut aggregator = GenericAggregator::<MyCandle, TimeRule, Trade>::new(time_rule);

    for t in &trades {
        if let Some(candle) = aggregator.update(t) {
            println!(
                "candle created with open: {}, high: {}, low: {}, close: {}",
                candle.open(),
                candle.high(),
                candle.low(),
                candle.close()
            );
        }
    }
}

Notice how the code is calling the 'open()', 'high()', 'low()' and 'close()' methods on the 'MyCandle' struct. These are getters automatically generated by the Candle macro, that have the same name as the field. In this case the 'Candle' derive macro for 'MyCandle' expands into this:

use trade_aggregation::{
    candle_components::{Close, High, Low, Open},
    *,
};

#[derive(Debug, Default, Clone)]
struct MyCandle {
    open: Open,
    high: High,
    low: Low,
    close: Close,
}

impl MyCandle {
    fn open(&self) -> f64 {
        self.open.value()
    }
    fn high(&self) -> f64 {
        self.high.value()
    }
    fn low(&self) -> f64 {
        self.low.value()
    }
    fn close(&self) -> f64 {
        self.close.value()
    }
}

impl ModularCandle<Trade> for MyCandle {
    fn update(&mut self, trade: &Trade) {
        self.open.update(trade);
        self.high.update(trade);
        self.low.update(trade);
        self.close.update(trade);
    }
    fn reset(&mut self) {
        self.open.reset();
        self.high.reset();
        self.low.reset();
        self.close.reset();
    }
}

See examples folder for more. Run examples using

cargo run --release --example aggregate_all_ohlc
cargo run --release --example streaming_aggregate_ohlc

Performance:

To run the benchmarks, written using criterion, run:

cargo bench

Here are some results running on a 12th gen Intel Core i7-12800H, aggregating 1 million trades into 1 minute candles:

Candle Time
Open 1 ms
OHLC 2.5 ms
All 8 ms

The more 'CandleComponent's you use, the longer it takes obviously.

Features

The serde feature exists which, when enabled, derives Serialize and Deserialize

TODOs:

  • Make generic over the data type storing the price (f64, f32, i64, Decimal, etc...)

Donations ๐Ÿ’ฐ ๐Ÿ’ธ

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

Monero (XMR) address:

47xMvxNKsCKMt2owkDuN1Bci2KMiqGrAFCQFSLijWLs49ua67222Wu3LZryyopDVPYgYmAnYkSZSz9ZW2buaDwdyKTWGwwb

monero

License

Copyright (C) 2020 <Mathis Wellmann [email protected]>

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

Commercial License

If you'd like to use this crate legally without the restrictions of the GNU AGPLv3 license, please contact me so we can quickly arrange a custom license.

trade_aggregation-rs's People

Contributors

dam5h avatar ivaaaan avatar mathiswellmann avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

trade_aggregation-rs's Issues

Wrong volume with AlignedTime rule aggregation

Hey. I have noticed that after using AlignedTime aggregation rule volume and amount of trades look wrong. Here is a simple test case:

https://github.com/ivaaaan/trade_aggregation-rs/blob/wrong-volume/src/aggregation_rules/aligned_time_rule.rs#L112

And test data file:
https://github.com/ivaaaan/trade_aggregation-rs/blob/wrong-volume/data/Bitstamp_BTCEUR_1M.csv

There are 10 trades between 00:00:00 and 00:00:01, however, aggregation rule includes 11th trade from the next minute as well.

Minor typo in lib line 136, 640 should be 240

Minor typo: 640 should be 240

The number of candles for 10 days is 240. The volume value of 41 is correct using 240.

Should read:

///     10 days of 1h candle -> 240 candles
///     assuming 9840 volume traded over 10 days
///     -> each candle should have 41 volume to produce 240 candles using volume aggregation

Thoughts on making Trade Generic or Adding a BidAskTrade?

Just came across this library, looks great, thank you!

I store tick data that has the bid / ask aggressor flag in it for order flow analysis. What are your thoughts on making the input Trade struct be be generic or just adding a variant that has additional information about whether or not it was a bid or ask trade?

As far as making Trade generic, I suppose a trait with getters for the required fields could work, then folks that have there own structures being read in wouldn't have to transform into Trade on every update call if they implement the trait.

Let me know what you think when you get a chance. Thanks again for this library. Have a nice day.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.