diff --git a/backend/secret_trader/Cargo.lock b/backend/secret_trader/Cargo.lock index 12e12da..a8840cd 100644 --- a/backend/secret_trader/Cargo.lock +++ b/backend/secret_trader/Cargo.lock @@ -2,6 +2,30 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "actix" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "543c47e7827f8fcc9d1445bd98ba402137bfce80ee2187429de49c52b5131bd3" +dependencies = [ + "actix-rt", + "actix_derive", + "bitflags", + "bytes", + "crossbeam-channel", + "futures-core", + "futures-sink", + "futures-task", + "futures-util", + "log", + "once_cell", + "parking_lot 0.11.2", + "pin-project-lite", + "smallvec", + "tokio", + "tokio-util 0.6.10", +] + [[package]] name = "actix-codec" version = "0.5.0" @@ -16,7 +40,7 @@ dependencies = [ "memchr", "pin-project-lite", "tokio", - "tokio-util", + "tokio-util 0.7.4", ] [[package]] @@ -85,6 +109,7 @@ version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ea16c295198e958ef31930a6ef37d0fb64e9ca3b6116e6b93a8bdae96ee1000" dependencies = [ + "actix-macros", "futures-core", "tokio", ] @@ -181,6 +206,17 @@ dependencies = [ "syn", ] +[[package]] +name = "actix_derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d44b8fee1ced9671ba043476deddef739dd0959bf77030b26b738cc591737a7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "adler" version = "1.0.2" @@ -231,6 +267,114 @@ dependencies = [ "libc", ] +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "async-channel" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-executor" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17adb73da160dfb475c183343c8cccd80721ea5a605d3eb57125f0a7b7a92d0b" +dependencies = [ + "async-lock", + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" +dependencies = [ + "async-channel", + "async-executor", + "async-io", + "async-lock", + "blocking", + "futures-lite", + "once_cell", + "tokio", +] + +[[package]] +name = "async-io" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c374dda1ed3e7d8f0d9ba58715f924862c63eae6849c92d3a18e7fbde9e2794" +dependencies = [ + "async-lock", + "autocfg", + "concurrent-queue", + "futures-lite", + "libc", + "log", + "parking", + "polling", + "slab", + "socket2", + "waker-fn", + "windows-sys", +] + +[[package]] +name = "async-lock" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8101efe8695a6c17e02911402145357e718ac92d3ff88ae8419e84b1707b685" +dependencies = [ + "event-listener", + "futures-lite", +] + +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-attributes", + "async-channel", + "async-global-executor", + "async-io", + "async-lock", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + [[package]] name = "async-stream" version = "0.3.3" @@ -252,6 +396,18 @@ dependencies = [ "syn", ] +[[package]] +name = "async-task" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" + +[[package]] +name = "atomic-waker" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "debc29dde2e69f9e47506b525f639ed42300fc014a3e007832592448fa8e4599" + [[package]] name = "autocfg" version = "1.1.0" @@ -279,6 +435,20 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blocking" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c67b173a56acffd6d2326fb7ab938ba0b00a71480e14902b2591c87bc5741e8" +dependencies = [ + "async-channel", + "async-lock", + "async-task", + "atomic-waker", + "fastrand", + "futures-lite", +] + [[package]] name = "brotli" version = "3.3.4" @@ -361,6 +531,15 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "concurrent-queue" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c278839b831783b70278b14df4d45e1beb1aad306c07bb796637de9a0e323e8e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -412,6 +591,25 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +dependencies = [ + "cfg-if", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -422,6 +620,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "ctor" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "cxx" version = "1.0.86" @@ -498,6 +706,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + [[package]] name = "fastrand" version = "1.8.0" @@ -595,6 +809,21 @@ version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" +[[package]] +name = "futures-lite" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + [[package]] name = "futures-macro" version = "0.3.25" @@ -657,6 +886,18 @@ dependencies = [ "wasi 0.11.0+wasi-snapshot-preview1", ] +[[package]] +name = "gloo-timers" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98c4a8d6391675c6b2ee1a6c8d06e8e2d03605c44cec1270675985a4c2a5500b" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "h2" version = "0.3.15" @@ -672,7 +913,7 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util", + "tokio-util 0.7.4", "tracing", ] @@ -865,6 +1106,15 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + [[package]] name = "language-tags" version = "0.3.2" @@ -927,6 +1177,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", + "value-bag", ] [[package]] @@ -1060,6 +1311,23 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + [[package]] name = "parking_lot" version = "0.12.1" @@ -1067,7 +1335,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.6", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", ] [[package]] @@ -1157,6 +1439,20 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +[[package]] +name = "polling" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22122d5ec4f9fe1b3916419b76be1e80bcb93f618d071d2edf841b137b2a2bd6" +dependencies = [ + "autocfg", + "cfg-if", + "libc", + "log", + "wepoll-ffi", + "windows-sys", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1323,12 +1619,16 @@ checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" name = "secret_trader" version = "0.1.0" dependencies = [ + "actix", + "actix-rt", "actix-web", + "async-std", "futures", "reqwest", "serde", "serde_json", "tdapi", + "uuid", ] [[package]] @@ -1590,7 +1890,8 @@ dependencies = [ "libc", "memchr", "mio", - "parking_lot", + "num_cpus", + "parking_lot 0.12.1", "pin-project-lite", "signal-hook-registry", "socket2", @@ -1631,6 +1932,20 @@ dependencies = [ "tokio-stream", ] +[[package]] +name = "tokio-util" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.4" @@ -1728,6 +2043,27 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "uuid" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" +dependencies = [ + "getrandom", + "rand", + "serde", +] + +[[package]] +name = "value-bag" +version = "1.0.0-alpha.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" +dependencies = [ + "ctor", + "version_check", +] + [[package]] name = "vcpkg" version = "0.2.15" @@ -1740,6 +2076,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + [[package]] name = "want" version = "0.3.0" @@ -1838,6 +2180,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "wepoll-ffi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" +dependencies = [ + "cc", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/backend/secret_trader/Cargo.toml b/backend/secret_trader/Cargo.toml index 47691b6..014e828 100644 --- a/backend/secret_trader/Cargo.toml +++ b/backend/secret_trader/Cargo.toml @@ -11,4 +11,8 @@ serde = "1.0.152" serde_json = "1.0.91" reqwest = "0.11.13" futures = "0.3.25" -actix-web = "4" \ No newline at end of file +actix-web = "4" +actix = "0.11.0" +actix-rt = "2.2" # <-- Runtime for actix +async-std = { version = "1.12.0", features = ["attributes", "tokio1"] } +uuid = {version= "1.2.2", features = ["serde", "fast-rng", "v4"]} \ No newline at end of file diff --git a/backend/secret_trader/TODO.txt b/backend/secret_trader/TODO.txt index 223e7d4..bc428e0 100644 --- a/backend/secret_trader/TODO.txt +++ b/backend/secret_trader/TODO.txt @@ -6,9 +6,9 @@ # API [ ] GET account IDs -[ ] GET open orders -[ ] POST new secret stop loss -[ ] POST cancel order +[X] GET open orders +[X] POST new secret stop loss +[X] POST cancel order # DB [ ] Store new account diff --git a/backend/secret_trader/src/main.rs b/backend/secret_trader/src/main.rs index 712dbbc..1e82b31 100644 --- a/backend/secret_trader/src/main.rs +++ b/backend/secret_trader/src/main.rs @@ -1,27 +1,137 @@ +use errors::DynResult; +use futures::future::join; +use futures::{join, try_join}; +use order::{MarketOrder, OffBookOrder}; +use trade_mgmt::{OpenOffBookOrders, Position, get_account_ids, get_open_positions}; use tdapi::account::tda_account::ApiAccount; +use std::sync::{Arc,Mutex}; +use std::time::{Duration, Instant}; +use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder}; +use async_std::task; +use futures::{ + future::FutureExt, // for `.fuse()` + pin_mut, + select, + executor::block_on +}; +use actix_rt::{spawn, time::interval}; mod trade_mgmt; mod errors; mod order; -#[actix_web::main] -async fn main() { - let TEST_ACT = "PNNX2GJXDTQNWY0SRCYGZMUHBFUUQHW7"; - let TEST_CALLBACK_URI = "https://localhost"; +#[actix_rt::main] +async fn main() -> std::io::Result<()>{ + + // We need to run a daemon that checks the open 'stop orders' every few seconds + // The orders need to be able to be sent to the loop from other treads + // We also need to communicate the deletion of orders - let mut tda = match ApiAccount::new(TEST_ACT, TEST_CALLBACK_URI) { - Ok(act) => act, - Err(e) => {println!("Failed to create TD act:\n{e:?}"); return;} - }; + // This channel will be used to send order info the the daemon + //let (tx, rx) = mpsc::channel(); - let act_nums = trade_mgmt::get_account_ids(&mut tda).await; - println!("act_nums = {:?}", act_nums); + let tda= web::Data::new(Mutex::new(ApiAccount::new("PNNX2GJXDTQNWY0SRCYGZMUHBFUUQHW7", "https://localhost").unwrap())); + let off_book_orders = web::Data::new(OpenOffBookOrders::new()); - let main_act = 686092736; + // This works + let obo = off_book_orders.clone(); + let tda_d = tda.clone(); - let buy_order = order::MarketOrder::new("SPY", 300.0, 1.0, order::Direction::BUY); - println!("buy_order = {:?}", buy_order); + spawn(test(tda_d)); + + HttpServer::new(move || { + App::new() + .app_data(off_book_orders.clone()) + .app_data(tda.clone()) + .service(return_account_ids) + .service(open_off_book) + .service(add_ob_order) + .service(cancel_ob_order) + .route("/hey", web::get().to(manual_hello)) + }) + .bind(("127.0.0.1", 8080))? + .run() + .await - let order_send = trade_mgmt::send_order(&mut tda, main_act, &buy_order).await; - println!("order_send = {:?}", order_send); } + +async fn api(off_book_orders: web::Data, tda_act: web::Data>>) -> std::io::Result<()> { + println!("Starting API.."); + HttpServer::new(move || { + App::new() + .app_data(off_book_orders.clone()) + .app_data(tda_act.clone()) + .service(return_account_ids) + .service(open_off_book) + .service(add_ob_order) + .service(cancel_ob_order) + .route("/hey", web::get().to(manual_hello)) + }) + .bind(("127.0.0.1", 8080))? + .run() + .await +} + +#[get("/")] +async fn hello() -> impl Responder { + HttpResponse::Ok().body("Hello world!") +} + +#[get("/openoffbook")] +async fn open_off_book(data: web::Data) -> impl Responder { + let mut open_off_book_orders = data.order_map.lock().unwrap(); + + let mut order_list = vec![]; + + for order in open_off_book_orders.values() { + order_list.push(serde_json::to_string(order).unwrap()); + } + HttpResponse::Ok().body( serde_json::to_string(&order_list).unwrap()) +} + +#[get("/accountids")] +async fn return_account_ids<'a>(data: web::Data>>) -> impl Responder { + println!("HIT"); + let mut tda = data.lock().unwrap(); + let account_ids = get_account_ids(&mut tda).await.unwrap(); + HttpResponse::Ok().body( serde_json::to_string(&account_ids).unwrap() ) +} + +#[post("/addorder/{target_price}")] +async fn add_ob_order(req_body: String, target_price: web::Path, data: web::Data) -> impl Responder { + let mut open_off_book_orders = data.order_map.lock().unwrap(); + let position: Position = serde_json::from_str(&req_body).unwrap(); + let new_order = OffBookOrder::from_position(position, target_price.into_inner()); + open_off_book_orders.insert(new_order.get_uuid(), new_order); + HttpResponse::Ok().body( r#"{"success": true}"# ) +} + +#[post("/cancelorder/{uuid}")] +async fn cancel_ob_order(uuid: web::Path, data: web::Data) -> impl Responder { + let mut open_off_book_orders = data.order_map.lock().unwrap(); + let removed = open_off_book_orders.remove(&uuid.into_inner()).is_some(); + HttpResponse::Ok().body( if removed {r#"{"success": true}"#} else {r#"{"success": false}"#} ) +} + +#[post("/echo")] +async fn echo(req_body: String) -> impl Responder { + HttpResponse::Ok().body(req_body) +} + +async fn manual_hello() -> impl Responder { + HttpResponse::Ok().body("Hey there!") +} + +async fn test<'a>(data: web::Data::>>) { + let mut interval = interval(Duration::from_secs(10)); + loop { + println!("Test"); + { + let mut tda = data.lock().unwrap(); + println!("Got mutex lock"); + let act = get_account_ids(&mut tda); + println!("act = {:?}", act.await); + } + interval.tick().await; + } +} \ No newline at end of file diff --git a/backend/secret_trader/src/order.rs b/backend/secret_trader/src/order.rs index 32bd41d..0b1b9dc 100644 --- a/backend/secret_trader/src/order.rs +++ b/backend/secret_trader/src/order.rs @@ -1,8 +1,11 @@ use serde::Deserialize; use serde::Serialize; +use uuid::Uuid; use tdapi::helpers::ToHashMap; +use crate::trade_mgmt::Position; +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum Direction { BUY, SELL @@ -15,6 +18,11 @@ impl Direction { } } } +impl Default for Direction { + fn default() -> Self { + Self::BUY + } +} #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -26,7 +34,7 @@ pub struct MarketOrder { pub order_leg_collection: Vec, } impl MarketOrder { - pub fn new(symbol: &str, price: f64, quantity: f64, direction: Direction) -> Self { + pub fn new(symbol: &str, quantity: f64, direction: Direction) -> Self { MarketOrder { order_type: "MARKET".to_string(), session: "SEAMLESS".to_string(), @@ -55,4 +63,50 @@ pub struct OrderLegCollection { pub struct Instrument { pub symbol: String, pub asset_type: String, +} + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct OffBookOrder { + pub symbol: String, + pub quantity: f64, + pub asset_type: String, + pub direction: Direction, + pub target_price: f64, + uuid : u128 +} +impl OffBookOrder { + pub fn new(symbol: String, quantity: f64, asset_type: String, direction: Direction, target_price: f64) -> Self { + let id = Uuid::new_v4().as_u128(); + OffBookOrder { symbol: symbol, quantity: quantity, asset_type: asset_type, direction: direction, target_price: target_price, uuid: id } + } + pub fn from_position(open_position: Position, target_price: f64) -> Self { + let id = Uuid::new_v4().as_u128(); + let mut quant = 0.0; + let mut dir = Direction::BUY; + + let symbol = open_position.instrument.symbol; + let asset_type = open_position.instrument.asset_type; + match open_position.long_quantity > open_position.short_quantity { + true => { + quant = open_position.long_quantity; + let direction = Direction::SELL; + }, + false => { + quant = open_position.short_quantity; + } + }; + + OffBookOrder { + symbol: symbol, + quantity: quant, + asset_type: asset_type, + direction: dir, + target_price: target_price, + uuid: id + } + } + pub fn get_uuid(&self) -> u128 { + self.uuid + } } \ No newline at end of file diff --git a/backend/secret_trader/src/trade_mgmt.rs b/backend/secret_trader/src/trade_mgmt.rs index 2dcd6ff..7a171f6 100644 --- a/backend/secret_trader/src/trade_mgmt.rs +++ b/backend/secret_trader/src/trade_mgmt.rs @@ -1,4 +1,6 @@ use std::collections::HashMap; +use actix_web::{web, App, HttpServer}; +use std::sync::Mutex; use serde::Deserialize; use serde::Serialize; use serde_json::Value; @@ -7,6 +9,17 @@ use tdapi::account::tda_account::ApiAccount; use tdapi::helpers::ToHashMap; use crate::errors::{DynResult}; use crate::order::MarketOrder; +use crate::order::OffBookOrder; + + +pub struct OpenOffBookOrders { + pub order_map: Mutex> +} +impl OpenOffBookOrders { + pub fn new() -> Self { + OpenOffBookOrders { order_map: Mutex::new(HashMap::new()) } + } +} #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -59,15 +72,26 @@ pub struct OpenOrderDetails { pub order_id: u64 } +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AccountId{ + id: u32, + value: f64 +} +impl AccountId { + pub fn new(id: u32, value: f64) -> Self { + AccountId { id: id, value: value } + } +} /// Returns current TD account ID's along with their current liquidation values -pub async fn get_account_ids<'a>( td_act: &mut ApiAccount<'a>) -> DynResult>{ +pub async fn get_account_ids<'a>( td_act: &mut ApiAccount<'a>) -> DynResult>{ let sec_acts = td_act.get_accounts().await?; let mut act_nums = vec![]; for act in sec_acts { - act_nums.push( (act.account_id.parse::()?, act.current_balances.liquidation_value)) + act_nums.push( AccountId::new(act.account_id.parse::()?, act.current_balances.liquidation_value)) } Ok(act_nums)