2024-05-09 09:52:52 -10:00
use std ::collections ::HashMap ;
use std ::cmp ::Ordering ;
use std ::cmp ::min ;
use fixed ::types ::U32F32 ;
#[ derive(Debug, Clone) ]
struct Offer {
sell_qty : u64 ,
sell_remain : u64 ,
buy_qty : u64 ,
}
trait Dumpable {
fn dump ( & self ) ;
}
impl Dumpable for Offer {
fn dump ( & self ) {
println! ( " Giving {} to get {} " , fxp_to_fp ( self . sell_qty ) , fxp_to_fp ( self . buy_qty ) ) ;
}
}
impl Offer {
fn dump ( self ) {
println! ( " Remaining: {} Price: {} " , self . sell_remain , fxp_to_fp ( fxp_div ( self . buy_qty , self . sell_qty ) ) ) ;
}
}
struct Market {
asset_name2num : HashMap < String , i32 > ,
asset_num2name : HashMap < i32 , String > ,
asset_count :i32 ,
offers : HashMap < ( i32 , i32 ) , PQueue < Offer > > ,
}
impl Market {
fn new ( ) -> Self {
Market {
asset_name2num : HashMap ::new ( ) ,
asset_num2name : HashMap ::new ( ) ,
asset_count :0 ,
offers : HashMap ::new ( )
}
}
fn register_asset ( & mut self , name :& str ) -> i32 {
self . asset_count + = 1 ;
self . asset_name2num . insert ( String ::from ( name ) , self . asset_count ) ;
self . asset_num2name . insert ( self . asset_count , String ::from ( name ) ) ;
self . asset_count
}
fn name_to_number ( & self , name :& str ) -> i32 {
* self . asset_name2num . get ( name ) . unwrap ( )
}
fn number_to_name ( & self , num :i32 ) -> & str {
& * self . asset_num2name . get ( & num ) . unwrap ( )
}
fn dump ( & self ) {
println! ( " Dumping Market: " ) ;
for ( key , value ) in & self . offers {
println! ( " Offers selling {} to buy {} : " , self . number_to_name ( key . 0 ) , self . number_to_name ( key . 1 ) ) ;
value . dump ( ) ;
}
}
fn make_offer ( & mut self , sell_type :i32 , buy_type :i32 , sell_qty_initial :u64 , buy_qty_initial :u64 ) // Dollars, Bitcoin, 64000, 1
2024-05-09 12:08:26 -10:00
{ // Comments assume someone is already selling 1 Bitcoin for 48000 USD (Bitcoin, Dollars, 1, 48000). Then someone comes along and bids $64000 for 1 Bitcoin (sells 64000 USD to buy 1 Bitcoin.
2024-05-09 09:52:52 -10:00
println! ( " Making offer to sell {} {} and get {} {} " , fxp_to_fp ( sell_qty_initial ) , self . number_to_name ( sell_type ) , fxp_to_fp ( buy_qty_initial ) , self . number_to_name ( buy_type ) ) ;
let mut sell_qty = sell_qty_initial ; // 64000 Dollars
let mut buy_qty = buy_qty_initial ; // 1 Bitcoin
let sell_rate = fxp_div ( buy_qty , sell_qty ) ;
let ap = ( buy_type , sell_type ) ;
while sell_qty > 0 {
if let Some ( asks ) = self . offers . get_mut ( & ap ) {
if asks . v . len ( ) > 0 {
let elt = & mut asks . v [ 0 ] ;
let ask_rate = fxp_div ( elt . buy_qty , elt . sell_qty ) ;
if sell_rate > = ask_rate { // Transact at ask_rate
2024-05-09 12:08:26 -10:00
/* let ask_transact =fxp_mult(elt.sell_remain,fxp_div(elt.sell_price,elt.sell_qty)); / / 48000 USD
2024-05-09 09:52:52 -10:00
let sell_transact = sell_qty ;
let transact = std ::cmp ::min ( ask_transact , sell_transact ) ; // 48000 USD
println! ( " Before: elt.sell_remain= {} sell_qty= {} transact= {} " , fxp_to_fp ( elt . sell_remain ) , fxp_to_fp ( sell_qty ) , fxp_to_fp ( transact ) ) ;
elt . sell_remain - = transact ;
sell_qty - = transact ;
println! ( " After: elt.sell_remain= {} sell_qty= {} " , elt . sell_remain , sell_qty ) ;
if elt . sell_remain = = 0 {
println! ( " Popping asks " ) ;
asks . pop ( ) ;
}
} else { break ; }
2024-05-09 12:08:26 -10:00
* /
}
else { break ; }
2024-05-09 09:52:52 -10:00
} else { break ; }
2024-05-09 12:08:26 -10:00
}
2024-05-09 09:52:52 -10:00
if sell_qty > 0 {
let ap = ( sell_type , buy_type ) ;
if let None = self . offers . get_mut ( & ap ) { self . offers . insert ( ap , PQueue ::new ( ) ) ; }
let mut bids = self . offers . get_mut ( & ap ) . unwrap ( ) ;
2024-05-09 12:08:26 -10:00
// let sell_price=fxp_div(fxp_mult(sell_price,sell_qty),sell_qty_initial);
// bids.insert(Offer { sell_qty:sell_qty, sell_remain:sell_qty, sell_price:sell_price } );
}
}
}
}
2024-05-09 09:52:52 -10:00
impl PartialOrd for Offer {
fn partial_cmp ( & self , other :& Self ) -> Option < Ordering > {
2024-05-09 12:08:26 -10:00
let ord0 = self . sell_qty / self . buy_qty ;
let ord1 = other . buy_qty / other . sell_qty ;
2024-05-09 09:52:52 -10:00
if ord0 < ord1 { Some ( Ordering ::Less ) }
else if ord0 > ord1 { Some ( Ordering ::Greater ) }
else { Some ( Ordering ::Equal ) }
}
}
impl PartialEq for Offer {
fn eq ( & self , other :& Self ) -> bool {
let ord0 = self . sell_price / self . sell_qty ;
let ord1 = other . sell_price / other . sell_qty ;
ord0 = = ord1
}
}
2024-05-09 12:08:26 -10:00
2024-05-09 09:52:52 -10:00
struct PQueue < T : Dumpable > {
v : Vec < T > ,
}
impl < T : Dumpable + std ::cmp ::PartialOrd + std ::fmt ::Debug > PQueue < T > {
fn new ( ) ->Self {
PQueue {
v : Vec ::new ( )
}
}
fn peek ( & self ) -> & T {
& self . v [ 0 ]
}
fn bubble_up ( & mut self , pos : usize ) {
if pos > 0 {
let parent = ( pos - 1 ) / 2 ;
if self . v [ parent ] < self . v [ pos ] {
self . v . swap ( parent , pos ) ;
self . bubble_up ( parent ) ;
}
}
}
fn trickle_down ( & mut self , pos : usize ) {
let mut pivot = pos ;
let child0 = pos * 2 + 1 ;
let child1 = pos * 2 + 2 ;
if child0 < self . v . len ( ) {
if self . v [ pos ] < self . v [ child0 ] { pivot = child0 ; }
if child1 < self . v . len ( ) {
if self . v [ pivot ] < self . v [ child1 ] { pivot = child1 ; }
}
if pivot ! = pos {
self . v . swap ( pivot , pos ) ;
self . trickle_down ( pivot ) ;
}
}
}
fn insert ( & mut self , item : T ) {
self . v . push ( item ) ;
self . bubble_up ( self . v . len ( ) - 1 ) ;
}
fn pop ( & mut self ) -> Option < T > {
if self . v . len ( ) = = 0 { None }
else {
let end = self . v . len ( ) - 1 ;
self . v . swap ( 0 , end ) ;
let rval = self . v . pop ( ) ;
self . trickle_down ( 0 ) ;
rval
}
}
fn dump ( & self ) {
for index in 0 .. self . v . len ( ) {
self . v [ index ] . dump ( ) ;
}
}
}
fn fxp_mult ( n0 :u64 , n1 :u64 ) ->u64 { ( n0 > > 32 ) * ( n1 > > 32 ) + ( n0 > > 32 ) * ( n1 & 0xFFFFFFFF ) + ( n0 & 0xFFFFFFFF ) * ( n1 > > 32 ) + ( n0 & 0xFFFFFFFF ) * ( n1 & 0xFFFFFFFF ) }
fn fxp_div ( n0 :u64 , n1 :u64 ) -> u64 { fxp_mult ( n0 , fxp_recip ( n1 ) ) }
fn fxp_from_int ( n :u32 ) -> u64 { ( n as u64 ) < < 32 }
fn fxp_recip ( n :u64 ) -> u64 { 0xFFFFFFFFFFFFFFFF u64 / n }
fn fxp_to_fp ( n :u64 ) -> f64 { ( n as f64 ) / ( 1 u64 < < 32 ) as f64 }
fn main ( ) {
let mut m = Market ::new ( ) ; // USD type is 1, EUR type is 2, BTC type is 10, ETH type is 11, SOL type is 12
let usd = m . register_asset ( " USD " ) ;
let btc = m . register_asset ( " BTC " ) ;
let n = 64000 u64 < < 32 ;
println! ( " Testing recip: {} {} {} " , fxp_to_fp ( n ) , fxp_recip ( n ) , fxp_to_fp ( fxp_recip ( fxp_recip ( n ) ) ) ) ;
m . make_offer ( btc , usd , fxp_from_int ( 1 ) , fxp_from_int ( 1 ) ) ;
m . dump ( ) ;
m . make_offer ( usd , btc , fxp_from_int ( 64000 ) , fxp_from_int ( 64000 ) ) ; // Buy 1 BTC for 64000 USD
m . dump ( ) ;
}