From 4250598a5f7764db075df52c8ce3badfdb4c5312 Mon Sep 17 00:00:00 2001 From: Teppy Date: Mon, 13 Jan 2025 13:34:26 -0500 Subject: [PATCH] changes --- 13.log | 13 ++++++ demo1.log | 11 +++++ demo13.log | 11 +++++ demo13x.log | 12 ++++++ demo2.log | 11 +++++ demo3.log | 11 +++++ demo4.log | 11 +++++ demox.log | 2 +- demoy.log | 11 +++++ demoz.log | 10 +++++ src/finum.rs | 4 ++ src/main.rs | 120 +++++++++++++++++++++++++++++++++++++-------------- 12 files changed, 194 insertions(+), 33 deletions(-) create mode 100644 13.log create mode 100644 demo1.log create mode 100644 demo13.log create mode 100644 demo13x.log create mode 100644 demo2.log create mode 100644 demo3.log create mode 100644 demo4.log create mode 100644 demoy.log create mode 100644 demoz.log diff --git a/13.log b/13.log new file mode 100644 index 0000000..febf665 --- /dev/null +++ b/13.log @@ -0,0 +1,13 @@ +AF 2 1 14F0117759 +AF 1 1 1D1E0D15FF +AF 2 1 70D4B3855 +OR 2 0 22E869AB9A 1 2327CD75D7 +AF 2 1 12F54589D1 +AF 1 0 16EC0573FE +AF 3 1 1DBA3B2F64 +AF 1 0 22A45121F2 +AF 3 0 BDB8CCB60 +OR 2 0 21CDCD2B81 1 2407EB5978 +AF 3 1 24E1249869 +OR 3 0 231B497C77 1 7C6A3D844 +OR 1 1 161753A88E 0 21069FA53A diff --git a/demo1.log b/demo1.log new file mode 100644 index 0000000..900f1de --- /dev/null +++ b/demo1.log @@ -0,0 +1,11 @@ +AT Teppy +AT Luni +AT Hamza +AA USD +AA BTC +SR 0 51EB851 0 0 0 +SR 1 51EB851 0 0 0 +AF 1 1 500000000 +AF 2 0 3D09000000000 +AF 3 0 3D09000000000 +OR 1 1 100000000 0 C35000000000 diff --git a/demo13.log b/demo13.log new file mode 100644 index 0000000..1d8431f --- /dev/null +++ b/demo13.log @@ -0,0 +1,11 @@ +AT Teppy +AT Hamza +AA USD +AA BTC +SR 0 0 0 0 33333333 +SR 1 0 0 0 33333333 +AF 1 1 500000000 +AF 2 0 3D09000000000 +AF 1 1 1D1E0D15FF +OR 2 0 231B497C77 1 7C6A3D844 +OR 1 1 161753A88E 0 21069FA53A diff --git a/demo13x.log b/demo13x.log new file mode 100644 index 0000000..4d3954c --- /dev/null +++ b/demo13x.log @@ -0,0 +1,12 @@ +AT Teppy +AT Hamza +AA USD +AA BTC +NOP SR 0 0 0 33333333 33333333 +NOP SR 1 0 0 33333333 33333333 +SR 0 11111111 22222222 33333333 44444444 +SR 1 18888888 28888888 38888888 48888888 +AF 1 1 400000000 +AF 2 0 3D09000000000 +OR 2 0 2800000000 1 100000000 +OR 1 1 100000000 0 1900000000 diff --git a/demo2.log b/demo2.log new file mode 100644 index 0000000..61510dd --- /dev/null +++ b/demo2.log @@ -0,0 +1,11 @@ +AT Teppy +AT Luni +AT Hamza +AA USD +AA BTC +SR 0 0 28F5C28 0 0 +SR 1 0 28F5C28 0 0 +AF 1 1 500000000 +AF 2 0 3D09000000000 +AF 3 0 3D09000000000 +OR 1 1 100000000 0 C35000000000 diff --git a/demo3.log b/demo3.log new file mode 100644 index 0000000..7fdf7a5 --- /dev/null +++ b/demo3.log @@ -0,0 +1,11 @@ +AT Teppy +AT Luni +AT Hamza +AA USD +AA BTC +SR 0 0 0 33333333 0 +SR 1 0 0 33333333 0 +AF 1 1 500000000 +AF 2 0 3D09000000000 +AF 3 0 3D09000000000 +OR 1 1 100000000 0 C35000000000 diff --git a/demo4.log b/demo4.log new file mode 100644 index 0000000..dc754b9 --- /dev/null +++ b/demo4.log @@ -0,0 +1,11 @@ +AT Teppy +AT Luni +AT Hamza +AA USD +AA BTC +SR 0 0 0 0 19999999 +SR 1 0 0 0 19999999 +AF 1 1 500000000 +AF 2 0 3D09000000000 +AF 3 0 3D09000000000 +OR 1 1 100000000 0 C35000000000 diff --git a/demox.log b/demox.log index 3d979bf..0e76014 100644 --- a/demox.log +++ b/demox.log @@ -3,9 +3,9 @@ AT Luni AT Hamza AA USD AA BTC +SR 0 51EB851 28F5C28 33333333 19999999 SR 1 51EB851 28F5C28 33333333 19999999 AF 1 1 500000000 AF 2 0 3D09000000000 AF 3 0 3D09000000000 -SR 0 51EB851 28F5C28 33333333 19999999 OR 1 1 100000000 0 C35000000000 diff --git a/demoy.log b/demoy.log new file mode 100644 index 0000000..0e76014 --- /dev/null +++ b/demoy.log @@ -0,0 +1,11 @@ +AT Teppy +AT Luni +AT Hamza +AA USD +AA BTC +SR 0 51EB851 28F5C28 33333333 19999999 +SR 1 51EB851 28F5C28 33333333 19999999 +AF 1 1 500000000 +AF 2 0 3D09000000000 +AF 3 0 3D09000000000 +OR 1 1 100000000 0 C35000000000 diff --git a/demoz.log b/demoz.log new file mode 100644 index 0000000..014aa9b --- /dev/null +++ b/demoz.log @@ -0,0 +1,10 @@ +AT Teppy +AT Luni +AT Hamza +AA USD +AA BTC +SR 0 51EB851 28F5C28 33333333 19999999 +SR 1 51EB851 28F5C28 33333333 19999999 +AF 1 1 500000000 +AF 2 0 3D09000000000 +AF 3 0 3D09000000000 diff --git a/src/finum.rs b/src/finum.rs index e630dae..9ad0545 100644 --- a/src/finum.rs +++ b/src/finum.rs @@ -36,6 +36,9 @@ impl FiNum { pub fn recip(&self) -> Self { FiNum((0x8000000000000000u64/self.0)<<1) } + pub fn fmt_pct2(&self) -> String { + format!("{:>5.2}%", (100.0*(self.0 as f64))/((1u64<<32) as f64)) + } pub fn fmt_recip(&self) -> String { if *self std::fmt::Result { +// write!(f, "{:08X}.{:08X}", self.0>>32,self.0&0xFFFFFFFF) write!(f, "{:.8}", (self.0 as f64)/((1u64<<32) as f64)) } } diff --git a/src/main.rs b/src/main.rs index 2bbd0c0..49c7713 100644 --- a/src/main.rs +++ b/src/main.rs @@ -50,6 +50,8 @@ use std::collections::HashMap; use std::cmp::Ordering; use rand::prelude::*; use rand::rngs::StdRng; +use std::time::Instant; + //use hashbrown::HashMap; mod finum; use finum::FiNum; @@ -110,8 +112,8 @@ struct Order { sell_qty: FiNum, sell_remain: FiNum, buy_qty: FiNum, - royalty_remain: FiNum, // Based on royalty1 - commission_remain: FiNum, // Based on commission1 + royalty_remain: FiNum, // Based on royalty1. The thing that is being sold + commission_remain: FiNum, // Based on commission1. The thing that is being sold owner: usize, order_id: usize, } @@ -200,17 +202,14 @@ impl RoyaltyTree { self.tree[index].lazy=FiNum::zero(); } else { let lazy=self.tree[index].lazy; -// println!("Index is {}, lazy.0 {}",index,lazy.serialize()); -// self.raw_dump(); let d1=if lazy>0.into() { lazy*self.weight_here(index)/self.weight_here_below(index) } else { FiNum::zero() }; let d02=lazy-d1; let index_left =wt_left (index).unwrap(); let index_right=wt_right(index).unwrap(); -// println!("D02 is {}, self.weight_here_below({}) is {}, self.weight_below({}) is {}",d02.serialize(),index_left,self.weight_here_below(index_left),index,self.weight_below(index)); if self.weight_below(index)>0.into() { let d0=if d02>0.into() { d02*self.weight_here_below(index_left)/self.weight_below(index) } else { FiNum::zero() }; let d2=d02-d0; - self.sanity(); +// self.sanity(); if !self.weight_here_below(index_left ).is_zero() { self.tree[index_left ].lazy+=d0; } else { self.spare_change+=d0; } if !self.weight_here_below(index_right).is_zero() { self.tree[index_right].lazy+=d2; } else { self.spare_change+=d2; } } @@ -220,7 +219,6 @@ impl RoyaltyTree { self.tree[index].acc+=d1; self.tree[index].lazy=FiNum::zero(); } -// println!("Royalty at {} is {}",index,self.tree[index].acc); self } fn sanity(&self) { @@ -243,7 +241,10 @@ impl RoyaltyTree { if self.next_entry==0 || FiNum::is_zero(self.tree[self.forefather()].weight) { self.spare_change+=amount } else { let ff=self.forefather(); - if self.weight_here_below(ff).is_zero() { self.spare_change+=amount } else { self.tree[ff].lazy+=amount }; + if self.weight_here_below(ff).is_zero() { self.spare_change+=amount } else { + self.tree[ff].lazy+=amount+self.spare_change; + self.spare_change=FiNum::zero() + }; } } // We really need two methods: remove an order and redistribute, remove some and return captured amount @@ -302,7 +303,6 @@ impl RoyaltyTree { self.expand_to(ff1*2); while ff0 Option { @@ -468,12 +488,12 @@ impl Market { let rt=self.royalties.get_mut(&ap.1).unwrap(); let indexr=rt.order_finder.get(&off.order_id).unwrap(); let royalty_amt=rt.get_royalty(*indexr); - println!(" {} @ {} ({}) OrderID: {} Royalties: {}", + println!(" {} @ {} ({}) OrderID: {} Royalties Accumulated: {} Royalties Offered {} Commissions Offered: {}", off.sell_remain, // off.buy_qty*off.sell_remain/off.sell_qty, (off.buy_qty/off.sell_qty).fmt_recip(), self.traders[off.owner as usize].name, off.order_id, - royalty_amt); + royalty_amt,off.royalty_remain,off.commission_remain); } } println!("Royalty Accum SpareChange"); @@ -515,6 +535,7 @@ impl Market { let cmd=Command::deserialize(line); if let Command::NOP(comment)=cmd { println!("{}",comment); } else { + println!("{}",cmd.explain(self)); let res=self.execute(&cmd); println!("{}",res.describe()); } @@ -549,11 +570,14 @@ impl Market { Result::ExecutedBatch(log) } */ - fn retract_order(&mut self, order_id:usize) -> Result { // Still need to credit back funds! But first fix the bug where we are creating commission0 from thin air in make_order (not charging seller) + fn retract_order(&mut self, order_id:usize) -> Result { // Still need to credit back funds! let pair=self.order_finder.get(&order_id).unwrap(); + let sell_type=pair.0; let queue=self.orders.get_mut(pair).unwrap(); let queue_index=*queue.order_finder.get(&order_id).unwrap(); let order=&queue.v[queue_index]; + let credit=order.sell_remain+order.royalty_remain+order.commission_remain; + self.traders[order.owner].add_balance(sell_type,credit); println!("Order owner is {}",order.owner); // Remove from royalties let rt=self.royalties.get_mut(&pair.0).unwrap(); @@ -582,10 +606,9 @@ impl Market { let mut commission_acc=FiNum::zero(); let new_order_id:usize; while execute_if_possible && buy_qty>FiNum::new(0) && self.orders.contains_key(&ap) && self.orders.get(&ap).unwrap().v.len()>0 { - let mut elt=self.orders.get(&ap).unwrap().v[0].clone(); + let elt=self.orders.get(&ap).unwrap().v[0].clone(); if sell_qty/buy_qty_initial>=elt.buy_qty/elt.sell_qty { // Transact at ask_rate let qty=std::cmp::min(elt.sell_remain,buy_qty); - elt.sell_remain-=qty; buy_qty-=qty; let pay_qty=qty*elt.buy_qty/elt.sell_qty; self.traders[owner ].sub_balance(sell_type,pay_qty); @@ -597,9 +620,10 @@ impl Market { let cq0=commission0_qty*pay_qty/sell_qty_initial; let rq1=royalty1_qty *pay_qty/sell_qty_initial; let cq1=commission1_qty*pay_qty/sell_qty_initial; -// println!("Transact at ask rate. Qty={} elt.sell_remain={} elt.royalty_remain={} elt.commission_remain={}",qty,elt.sell_remain,elt.royalty_remain,elt.commission_remain); + //println!("Transact at ask rate. Qty={} elt.sell_remain={} elt.royalty_remain={} elt.commission_remain={}",qty,elt.sell_remain,elt.royalty_remain,elt.commission_remain); let rq2=if !elt.sell_remain.is_zero() { elt.royalty_remain *qty/elt.sell_remain } else { FiNum::zero() }; let cq2=if !elt.sell_remain.is_zero() { elt.commission_remain*qty/elt.sell_remain } else { FiNum::zero() }; + //elt.sell_remain-=qty; royalty_acc+=rq0+rq1; commission_acc+=cq0+cq1; royalty0_qty-=rq0; @@ -609,17 +633,23 @@ impl Market { self.royalties.entry(sell_type).or_insert(RoyaltyTree::new()).add_royalty(rq0+rq1); self.royalties.entry(buy_type) .or_insert(RoyaltyTree::new()).add_royalty(rq2); let top_order=self.orders.get_mut(&ap).unwrap().peek(); + //println!("top_order.commission_remain={} cq2={} elt.commission_remain={} qty={} elt.sell_remain={}",top_order.commission_remain,cq2,elt.commission_remain,qty,elt.sell_remain); top_order.royalty_remain-=rq2; top_order.commission_remain-=cq2; + //println!("Crediting {} commissions to house {}+{}+{}",sell_type,cq0,cq1,cq2); + self.traders[0].add_balance(sell_type,cq0+cq1); self.traders[0].add_balance(buy_type,cq2); - if elt.sell_remain==0.into() { // deal with pennies stored in royalty_remain and commission_remain - self.traders[0].add_balance(buy_type,top_order.commission_remain); - self.royalties.entry(buy_type).or_insert(RoyaltyTree::new()).add_royalty(top_order.royalty_remain); - self.royalties.get_mut(&sell_type).unwrap().remove_order_id(top_order.order_id); + if elt.sell_remain==qty { // deal with pennies stored in royalty_remain and commission_remain + //if !top_order.commission_remain.is_zero() { println!("Little commission? {} ",top_order.commission_remain); } + let rq3=top_order.royalty_remain; + let cq3=top_order.commission_remain; + self.royalties.get_mut(&buy_type).unwrap().remove_order_id(top_order.order_id); self.order_finder.remove(&top_order.order_id); self.traders[top_order.owner].order_finder.remove(&top_order.order_id); self.orders.get_mut(&ap).unwrap().pop(); // This removes id (which is stored as part of the Order) from self.order's finder self.order_count-=1; + self.traders[0].add_balance(buy_type,cq3); + self.royalties.entry(buy_type).or_insert(RoyaltyTree::new()).add_royalty(rq3); } else { top_order.sell_remain-=qty; } @@ -637,8 +667,8 @@ impl Market { self.next_order_id+=1; // Pay royalties to existing orders on the sell size - self.royalties.entry(sell_type).or_insert(RoyaltyTree::new()).add_royalty(royalty0_qty+royalty1_qty); - royalty_acc+=royalty0_qty+royalty1_qty; + self.royalties.entry(sell_type).or_insert(RoyaltyTree::new()).add_royalty(royalty0_qty); + royalty_acc+=royalty0_qty; // Create a new entry in the RoyaltyTree to accumulate for this Order let rt=self.royalties.entry(buy_type).or_insert(RoyaltyTree::new()); @@ -649,15 +679,18 @@ impl Market { // Insert the new order in the priority queue (OrderQueue) let neworder=Order { owner:owner, sell_qty:sell_qty_remain, sell_remain:sell_qty_remain, buy_qty:buy_qty, royalty_remain:royalty1_qty, commission_remain:commission1_qty, order_id:id }; bids.insert(neworder); + royalty_acc+=royalty1_qty; + commission_acc+=commission1_qty; self.order_count+=1; self.order_finder.insert(id,(sell_type,buy_type)); self.traders[owner].sub_balance(sell_type,sell_qty_remain); - commission_acc+=commission0_qty+commission1_qty; + self.traders[owner].sub_balance(sell_type,commission0_qty); + self.traders[0].add_balance(sell_type,commission0_qty); self.traders[owner].order_finder.insert(id,(sell_type,buy_type)); log.push(format!("Moved {} {} ({}) to market",sell_qty_remain,self.number_to_name(sell_type),self.traders[owner].name)); } } - self.traders[0].add_balance(sell_type,commission_acc); +// self.traders[0].add_balance(sell_type,commission_acc); self.traders[owner].sub_balance(sell_type,royalty_acc+commission_acc); log.push(format!("Paid {} {} in royalties and {} {} ({}) in commissions",royalty_acc ,self.number_to_name(sell_type), commission_acc,self.number_to_name(sell_type),self.traders[owner].name)); @@ -947,6 +980,28 @@ impl Command { _ => format!("NOP (This should never happen)"), } } + fn explain(&self, m: &Market) -> String { + match self { + Self::AddTrader { user: name } => format!("addtrader {}",name), + Self::AddAsset { asset: name } => format!("addasset {}",name), + Self::SetRoyalty { asset_id, roy0, com0 , roy1 , com1 } + => format!("setroyalty {} {} {} {} {}",m.number_to_name(*asset_id),roy0,com0,roy1,com1), + Self::AddFunds { user_id, asset_id, amt } + => format!("addfunds {} {} {}",m.traders[*user_id].name,m.number_to_name(*asset_id),amt), + Self::SubFunds { user_id, asset_id , amt } + => format!("subfunds {} {} {}",m.traders[*user_id].name,m.number_to_name(*asset_id),amt), + Self::Order { user_id, sell_type, sell_qty, buy_type, buy_qty } + => format!("order {} {} {} {} (as {})",sell_qty,m.number_to_name(*sell_type),buy_qty,m.number_to_name(*buy_type),m.traders[*user_id].name), + Self::OrderBatch { user_id, sell_type, sell_qty, buy_type, buy_qty } + => format!("orderbatch {} {} {} {} (as {})",sell_qty,m.number_to_name(*sell_type),buy_qty,m.number_to_name(*buy_type),m.traders[*user_id].name), + Self::ExecuteBatch { asset_type0, strike0, asset_type1, strike1 } + => format!("executebatch {} {} {} {}",strike0,m.number_to_name(*asset_type0),strike1,m.number_to_name(*asset_type1)), + Self::RetractOrder { order_id } => format!("retract {}",order_id), + Self::Error(str) => format!("NOP Error: {}",str), + Self::NOP(str) => format!("NOP {}",clean(str)), + _ => format!("NOP (This should never happen)"), + } + } fn deserialize(line: String) -> Self { let tokens: Vec<&str> = line.split_whitespace().collect(); match tokens.as_slice() { @@ -1010,21 +1065,18 @@ impl Market { Command::SetRoyalty { asset_id,roy0,com0,roy1,com1 } => { if *roy0+*com0+*roy1+*com1 { self.add_trader_balance(*user_id,*asset_id,*amt); -// println!("Added {} {} to {}",*amt,self.number_to_asset(*asset_id).name,self.traders[*user_id].name); Result::FundsRemaining(self.get_trader_balance(*user_id,*asset_id)) } Command::SubFunds { user_id,asset_id,amt } => { if *amt>self.get_trader_balance(*user_id,*asset_id) { Result::Error(format!("Not enough {} in {}",asset_id,user_id)) } else { self.sub_trader_balance(*user_id,*asset_id,*amt); - println!("Subtracted {} {} from {}",*amt,self.number_to_asset(*asset_id).name,self.traders[*user_id].name); Result::FundsRemaining(self.get_trader_balance(*user_id,*asset_id)) } } @@ -1161,7 +1213,8 @@ fn interactive(m: &mut Market, mut out: Option) { Ok(input) => { let tokens: Vec<&str> = input.split_whitespace().collect(); let cmd:Command=match tokens.as_slice() { - ["dump"] => { m.dump(); m.sanity_check(); Command::None }, + ["dump"] => { m.dump(); Command::None }, + ["sanity"] => { m.sanity_check(); Command::None }, ["randomorder"] => { println!("Random OrderID: {:?}",m.random_order_id()); Command::None } ["login", username] => { if let Some(t)=m.trader_name2num.get_mut(*username) { trader=*t; println!("Logged in as {}",m.traders[trader].name) } else { println!("Trader {} not found.",username) } @@ -1198,6 +1251,7 @@ fn interactive(m: &mut Market, mut out: Option) { } ["randomcommands", qty] => { let qty:u32=qty.parse().unwrap(); + let start = Instant::now(); for i in 0..qty { let cmd=m.random_command(); // println!("RandomCommand #{}: {}",1+i,cmd.serialize()); @@ -1210,6 +1264,8 @@ fn interactive(m: &mut Market, mut out: Option) { let res=m.execute(&cmd); // println!("Result: {}",res.describe()); } + let duration = start.elapsed(); + println!("Ran {} commands in {:?}",qty,duration); Command::None }, ["quit"] => { return },