diff --git a/Cargo.lock b/Cargo.lock index 285ba48..f83f923 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1105,6 +1105,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + [[package]] name = "deranged" version = "0.3.11" @@ -1790,9 +1796,12 @@ dependencies = [ "log", "serde", "serde_derive", + "serde_json", "time", "tokio", "toml", + "tungstenite", + "url", ] [[package]] @@ -1925,6 +1934,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -1932,7 +1952,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", "pin-project-lite", ] @@ -1964,7 +1984,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http", + "http 0.2.12", "http-body", "httparse", "httpdate", @@ -3180,6 +3200,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "serde_json" +version = "1.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_repr" version = "0.1.19" @@ -3641,6 +3672,26 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8" +[[package]] +name = "tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", + "httparse", + "log", + "native-tls", + "rand", + "sha1", + "thiserror", + "url", + "utf-8", +] + [[package]] name = "type-map" version = "0.5.0" @@ -3717,6 +3768,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf8parse" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index ebf9565..c662b74 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,3 +26,6 @@ egui_plot = "0.27.2" eframe = "0.27.2" ibapi = "0.4.3" colored = "2.1.0" +tungstenite = {version="0.21.0", features=["native-tls"]} +url = "2.5.0" +serde_json = "1.0.117" diff --git a/README.md b/README.md index c28e59f..aa05c4b 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,8 @@ All in one trading engine ### Paper trading & live trading - [x] Single live broker: IBKR - [x] Live trading with single broker -- [ ] Async +- [ ] AsyncIO +- [ ] Websocket: Constant polling is not recommended to get real-time market data. Use websocket instead ## Demo ```shell diff --git a/src/cmds/backtest.rs b/src/cmds/backtest.rs index d205156..236f1da 100644 --- a/src/cmds/backtest.rs +++ b/src/cmds/backtest.rs @@ -42,9 +42,9 @@ impl Command for BackTestCommand { async fn backtest(symbol: &str) -> Result<()> { let mut green = Green::new() .set_mode(GreenModeType::Backtest) - .add_broker(100_000.0) - .add_data_feed(symbol) - .add_strategy(SimpleStrategy{}) + .set_broker(100_000.0) + .set_data_feed(symbol) + .set_strategy(SimpleStrategy{}) .build(); green.run(); diff --git a/src/green/broker/alpaca/alpaca.rs b/src/green/broker/alpaca/alpaca.rs new file mode 100644 index 0000000..c0170ea --- /dev/null +++ b/src/green/broker/alpaca/alpaca.rs @@ -0,0 +1,10 @@ +use url::Url; +use tungstenite::{connect, Message}; +use serde_json; + +const BASE_URL: &str = "wss://stream.data.alpaca.markets/v2/test"; + +fn main() { + let (mut socket, response) = connect(Url::parse(BASE_URL).unwrap()).expect("Can't connect"); + println!("{:#?}", response); +} \ No newline at end of file diff --git a/src/green/broker/alpaca/mod.rs b/src/green/broker/alpaca/mod.rs new file mode 100644 index 0000000..59cac0d --- /dev/null +++ b/src/green/broker/alpaca/mod.rs @@ -0,0 +1 @@ +mod alpaca; \ No newline at end of file diff --git a/src/green/broker/backtest.rs b/src/green/broker/ibkr/backtest.rs similarity index 100% rename from src/green/broker/backtest.rs rename to src/green/broker/ibkr/backtest.rs diff --git a/src/green/broker/live.rs b/src/green/broker/ibkr/live.rs similarity index 100% rename from src/green/broker/live.rs rename to src/green/broker/ibkr/live.rs diff --git a/src/green/broker/mod.rs b/src/green/broker/mod.rs index 650c159..5de0ea5 100644 --- a/src/green/broker/mod.rs +++ b/src/green/broker/mod.rs @@ -3,4 +3,5 @@ pub trait Broker{ } pub mod live; -pub mod backtest; \ No newline at end of file +pub mod backtest; +mod alpaca; \ No newline at end of file diff --git a/src/green/green.rs b/src/green/green.rs index d2400e0..aea50d0 100644 --- a/src/green/green.rs +++ b/src/green/green.rs @@ -125,7 +125,7 @@ impl Green { impl GreenBuilder { - pub fn add_data_feed(&mut self, symbol: &str) -> &mut GreenBuilder{ + pub fn set_data_feed(&mut self, symbol: &str) -> &mut GreenBuilder{ // TODO: refactor code let contract = Contract { symbol: "USD".to_owned(), @@ -146,7 +146,7 @@ impl GreenBuilder { self.mode = mode; self } - pub fn add_broker(&mut self, cash: f64) -> &mut GreenBuilder { + pub fn set_broker(&mut self, cash: f64) -> &mut GreenBuilder { self.broker = match self.mode { GreenModeType::Backtest => BackTestBroker{ cash: Vec::from([cash]), @@ -159,7 +159,7 @@ impl GreenBuilder { }; self } - pub fn add_strategy(&mut self, strategy: SimpleStrategy) -> &mut GreenBuilder{ + pub fn set_strategy(&mut self, strategy: SimpleStrategy) -> &mut GreenBuilder{ self.strategy = strategy; self } diff --git a/src/main.rs b/src/main.rs index cd98d33..72a4b2a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,6 +44,6 @@ async fn main() -> anyhow::Result<()> { Some(("backtest", sub_m)) => Ok(BackTestCommand::handler(sub_m).await?), Some(("paper-trading", sub_m)) => Ok(PaperTradingCommand::handler(sub_m).await?), Some(("live-trading", sub_m)) => Ok(LiveTradingCommand::handler(sub_m).await?), - _ => Err(anyhow::Error::msg("Miss arguments. Please access Makefile to get instructions")), + _ => Err(anyhow::Error::msg("Miss arguments. Please open Makefile to get instructions")), } }