#![allow(clippy::unwrap_used, clippy::expect_used)]
use rust_decimal::Decimal;
use rust_decimal_macros::dec;
use rustrade::{
EngineEvent,
engine::{
audit::state_replica::StateReplicaManager,
clock::LiveClock,
state::{
global::DefaultGlobalData,
instrument::{data::DefaultInstrumentMarketData, filter::InstrumentFilter},
trading::TradingState,
},
},
logging::init_logging,
risk::DefaultRiskManager,
statistic::time::Daily,
strategy::DefaultStrategy,
system::{
builder::{AuditMode, EngineFeedMode, SystemArgs, SystemBuilder},
config::SystemConfig,
},
};
use rustrade_data::{
streams::builder::dynamic::indexed::init_indexed_multi_exchange_market_stream,
subscription::SubKind,
};
use rustrade_instrument::index::IndexedInstruments;
use rustrade_integration::collection::snapshot::SnapUpdates;
use std::{fs::File, io::BufReader, time::Duration};
const FILE_PATH_SYSTEM_CONFIG: &str = "rustrade/examples/config/system_config.json";
const RISK_FREE_RETURN: Decimal = dec!(0.05);
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
init_logging();
let SystemConfig {
instruments,
executions,
} = load_config()?;
let instruments = IndexedInstruments::new(instruments);
let market_stream = init_indexed_multi_exchange_market_stream(
&instruments,
&[SubKind::PublicTrades, SubKind::OrderBooksL1],
)
.await?;
let args = SystemArgs::new(
&instruments,
executions,
LiveClock,
DefaultStrategy::default(),
DefaultRiskManager::default(),
market_stream,
DefaultGlobalData,
|_| DefaultInstrumentMarketData::default(),
);
let mut system = SystemBuilder::new(args)
.engine_feed_mode(EngineFeedMode::Iterator)
.audit_mode(AuditMode::Enabled)
.trading_state(TradingState::Disabled)
.build::<EngineEvent, _>()?
.init_with_runtime(tokio::runtime::Handle::current())
.await?;
let SnapUpdates {
snapshot: audit_snapshot,
updates: audit_updates,
} = system.audit.take().unwrap();
let mut state_replica_manager = StateReplicaManager::new(audit_snapshot, audit_updates);
let state_replica_task = tokio::task::spawn_blocking(move || {
state_replica_manager.run().unwrap();
state_replica_manager
});
system.trading_state(TradingState::Enabled);
tokio::time::sleep(Duration::from_secs(5)).await;
system.cancel_orders(InstrumentFilter::None);
system.close_positions(InstrumentFilter::None);
let (engine, _shutdown_audit) = system.shutdown().await?;
state_replica_task.await?;
let trading_summary = engine
.trading_summary_generator(RISK_FREE_RETURN)
.generate(Daily);
trading_summary.print_summary();
Ok(())
}
fn load_config() -> Result<SystemConfig, Box<dyn std::error::Error>> {
let file = File::open(FILE_PATH_SYSTEM_CONFIG)?;
let reader = BufReader::new(file);
let config = serde_json::from_reader(reader)?;
Ok(config)
}