1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
//! # 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.
//!
//! See [`Readme`].
//!
//! ## 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. The Engine can be **controlled by issuing Commands** over the Engine's command_tx. Similarly,
//! the **Engine's Events can be listened to using the event_rx** (useful for event-sourcing). 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.
//!
//! [`Barter`]: https://github.com/barter-rs/barter-rs
//! [`Barter-Data`]: https://crates.io/crates/barter-data
//! [`Readme`]: https://crates.io/crates/barter
//!
//! ## Getting Started
//! ### Data Handler
//! ```
//!
//!
//! use barter::{data::{Feed, historical, MarketGenerator}, test_util};
//! use barter_integration::model::Side;
//!
//! let mut data = historical::MarketFeed::new([test_util::market_event_trade(Side::Buy)].into_iter());
//!
//! loop {
//!     let market_event = match data.next() {
//!         Feed::Next(market_event) => market_event,
//!         Feed::Finished => break,
//!         Feed::Unhealthy => continue,
//!     };
//! }
//! ```
//!
//! ### Strategy
//! ```
//! use barter::{
//!     strategy::{SignalGenerator, example::{Config as StrategyConfig, RSIStrategy}},
//!     test_util,
//! };
//! use barter_integration::model::Side;
//!
//! let config = StrategyConfig {
//!     rsi_period: 14,
//! };
//!
//! let mut strategy = RSIStrategy::new(config);
//!
//! let market_event = test_util::market_event_trade(Side::Buy);
//!
//! let signal_event = strategy.generate_signal(&market_event);
//! ```
//!
//! ### Portfolio
//! ```
//! use barter::{
//!     portfolio::{
//!         MarketUpdater, OrderGenerator, FillUpdater,
//!         portfolio::{PortfolioLego, MetaPortfolio},
//!         repository::in_memory::InMemoryRepository,
//!         allocator::DefaultAllocator,
//!         risk::DefaultRisk,
//!     },
//!     statistic::summary::{
//!         pnl::PnLReturnSummary,
//!         trading::{Config as StatisticConfig, TradingSummary},
//!     },
//!     event::Event,
//!     test_util,
//! };
//! use barter_integration::model::{Market, instrument::kind::InstrumentKind};
//! use std::marker::PhantomData;
//! use uuid::Uuid;
//!
//! let components = PortfolioLego {
//!     engine_id: Uuid::new_v4(),
//!     markets: vec![Market::new("binance", ("btc", "usdt", InstrumentKind::Spot))],
//!     repository: InMemoryRepository::new(),
//!     allocator: DefaultAllocator{ default_order_value: 100.0 },
//!     risk: DefaultRisk{},
//!     starting_cash: 10000.0,
//!     statistic_config: StatisticConfig {
//!         starting_equity: 10000.0 ,
//!         trading_days_per_year: 365,
//!         risk_free_return: 0.0
//!     },
//!     _statistic_marker: PhantomData::<TradingSummary>::default()
//! };
//!
//! let mut portfolio = MetaPortfolio::init(components).unwrap();
//!
//! let some_event = Event::OrderNew(test_util::order_event());
//!
//! match some_event {
//!     Event::Market(market) => {
//!         portfolio.update_from_market(&market);
//!     }
//!     Event::Signal(signal) => {
//!         portfolio.generate_order(&signal);
//!     }
//!     Event::SignalForceExit(signal) => {
//!         portfolio.generate_exit_order(signal);
//!     }
//!     Event::Fill(fill) => {
//!         portfolio.update_from_fill(&fill);
//!     }
//!     _ => {}
//! }
//! ```
//!
//! ### Execution
//! ```
//! use barter::{
//!     test_util,
//!     portfolio::OrderEvent,
//!     execution::{
//!         simulated::{Config as ExecutionConfig, SimulatedExecution},
//!         Fees, ExecutionClient,
//!     }
//! };
//!
//! let config = ExecutionConfig {
//!     simulated_fees_pct: Fees {
//!         exchange: 0.1,
//!         slippage: 0.05, // Simulated slippage modelled as a Fee
//!         network: 0.0,
//!     }
//! };
//!
//! let mut execution = SimulatedExecution::new(config);
//!
//! let order_event = test_util::order_event();
//!
//! let fill_event = execution.generate_fill(&order_event);
//! ```
//!
//! ### Statistic
//! ```
//! use barter::{
//!     test_util,
//!     portfolio::position::Position,
//!     statistic::summary::{
//!         trading::{Config as StatisticConfig, TradingSummary},
//!         Initialiser, PositionSummariser, TableBuilder
//!     }
//! };
//!
//! // Do some automated trading with barter components that generates a vector of closed Positions
//! let positions = vec![test_util::position(), test_util::position()];
//!
//! let config = StatisticConfig {
//!     starting_equity: 10000.0,
//!     trading_days_per_year: 253,
//!     risk_free_return: 0.5,
//! };
//!
//! let mut trading_summary = TradingSummary::init(config);
//!
//! trading_summary.generate_summary(&positions);
//!
//! trading_summary
//!     .table("Total")
//!     .printstd();
//! ```
//!
//! ### Engine & Traders
//! [See Readme Engine Example](https://crates.io/crates/barter#example)

#![warn(
    unused,
    missing_debug_implementations,
    missing_copy_implementations,
    rust_2018_idioms,
    // missing_docs
)]
#![allow(clippy::type_complexity)]
#![allow(clippy::module_inception)]

/// Defines a MarketEvent, and provides the Continuer and MarketGenerator traits for
/// handling the generation of them. Contains implementations such as the (tick-by_tick)
/// LiveTradeHandler, and HistoricalCandleHandler that generates a market feed and acts as the
/// system heartbeat.
pub mod data;

/// Defines a SignalEvent and SignalForceExit, as well as the SignalGenerator trait for handling the
/// generation of them. Contains an example RSIStrategy implementation that analyses a MarketEvent
/// and may generate a new advisory SignalEvent to be analysed by the Portfolio OrderGenerator.
pub mod strategy;

/// Defines useful data structures such as an OrderEvent and Position. The Portfolio must
/// interact with MarketEvents, SignalEvents, OrderEvents, and FillEvents. The useful traits
/// MarketUpdater, OrderGenerator, & FillUpdater are provided that define the interactions
/// with these events. Contains a MetaPortfolio implementation that persists state in a
/// generic Repository. This also contains example implementations of an OrderAllocator &
/// OrderEvaluator, which help the Portfolio make decisions on whether to generate OrderEvents and
/// of what size.
pub mod portfolio;

/// Defines a FillEvent, and provides a useful trait FillGenerator for handling the generation
/// of them. Contains an example SimulatedExecution implementation that simulates live broker
/// execution.
pub mod execution;

/// Defines an Event enum that contains variants that are vital to the trading event loop
/// (eg/ MarketEvent). Other variants communicate work done by the system (eg/ FillEvent), as well
/// as changes in system state (eg/ PositionUpdate).
pub mod event;

/// Defines various iterative statistical methods that can be used to calculate trading performance
/// metrics in one-pass. A trading performance summary implementation has been provided containing
/// several key metrics such as Sharpe Ratio, Calmar Ratio, and Max Drawdown.
pub mod statistic;

/// Multi-threaded trading Engine capable of trading with an arbitrary number market pairs. Contains
/// a Trader for each Market pair that consists of it's own Data, Strategy &
/// Execution components, as well as shared access to a global Portfolio.
pub mod engine;

#[macro_use]
extern crate prettytable;

pub mod test_util {
    use crate::{
        data::MarketMeta,
        execution::{Fees, FillEvent},
        portfolio::{position::Position, OrderEvent, OrderType},
        strategy::{Decision, Signal},
    };
    use barter_data::{
        event::{DataKind, MarketEvent},
        exchange::ExchangeId,
        subscription::{candle::Candle, trade::PublicTrade},
    };
    use barter_integration::model::{
        instrument::{kind::InstrumentKind, Instrument},
        Exchange, Side,
    };
    use chrono::Utc;
    use std::ops::Add;

    /// Build a [`MarketEvent`] of [`DataKind::PublicTrade`](DataKind) with the provided [`Side`].
    pub fn market_event_trade(side: Side) -> MarketEvent<DataKind> {
        MarketEvent {
            exchange_time: Utc::now(),
            received_time: Utc::now(),
            exchange: Exchange::from(ExchangeId::BinanceSpot),
            instrument: Instrument::from(("btc", "usdt", InstrumentKind::Spot)),
            kind: DataKind::Trade(PublicTrade {
                id: "trade_id".to_string(),
                price: 1000.0,
                amount: 1.0,
                side,
            }),
        }
    }

    /// Build a [`MarketEvent`] of [`DataKind::Candle`](DataKind).
    pub fn market_event_candle() -> MarketEvent<DataKind> {
        let now = Utc::now();
        MarketEvent {
            exchange_time: now,
            received_time: now.add(chrono::Duration::milliseconds(200)),
            exchange: Exchange::from(ExchangeId::BinanceSpot),
            instrument: Instrument::from(("btc", "usdt", InstrumentKind::Spot)),
            kind: DataKind::Candle(Candle {
                close_time: now,
                open: 960.0,
                high: 1100.0,
                low: 950.0,
                close: 1000.0,
                volume: 100000.0,
                trade_count: 1000,
            }),
        }
    }

    /// Build a [`Signal`].
    pub fn signal() -> Signal {
        Signal {
            time: Utc::now(),
            exchange: Exchange::from("binance"),
            instrument: Instrument::from(("btc", "usdt", InstrumentKind::Spot)),
            signals: Default::default(),
            market_meta: Default::default(),
        }
    }

    /// Build an [`OrderEvent`] to buy 1.0 contract.
    pub fn order_event() -> OrderEvent {
        OrderEvent {
            time: Utc::now(),
            exchange: Exchange::from("binance"),
            instrument: Instrument::from(("eth", "usdt", InstrumentKind::Spot)),
            market_meta: MarketMeta::default(),
            decision: Decision::default(),
            quantity: 1.0,
            order_type: OrderType::default(),
        }
    }

    /// Build a [`FillEvent`] for a single bought contract.
    pub fn fill_event() -> FillEvent {
        FillEvent {
            time: Utc::now(),
            exchange: Exchange::from("binance"),
            instrument: Instrument::from(("eth", "usdt", InstrumentKind::Spot)),
            market_meta: Default::default(),
            decision: Decision::default(),
            quantity: 1.0,
            fill_value_gross: 100.0,
            fees: Fees::default(),
        }
    }

    /// Build a [`Position`].
    pub fn position() -> Position {
        Position {
            position_id: "engine_id_trader_{}_{}_position".to_owned(),
            exchange: Exchange::from("binance"),
            instrument: Instrument::from(("eth", "usdt", InstrumentKind::Spot)),
            meta: Default::default(),
            side: Side::Buy,
            quantity: 1.0,
            enter_fees: Default::default(),
            enter_fees_total: 0.0,
            enter_avg_price_gross: 100.0,
            enter_value_gross: 100.0,
            exit_fees: Default::default(),
            exit_fees_total: 0.0,
            exit_avg_price_gross: 0.0,
            exit_value_gross: 0.0,
            current_symbol_price: 100.0,
            current_value_gross: 100.0,
            unrealised_profit_loss: 0.0,
            realised_profit_loss: 0.0,
        }
    }
}