changes
This commit is contained in:
110
src/main.rs
110
src/main.rs
@@ -46,12 +46,9 @@ use std::io::{self, BufRead, Write};
|
|||||||
use std::env;
|
use std::env;
|
||||||
//use std::collections::HashMap;
|
//use std::collections::HashMap;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use rand::rngs::StdRng;
|
use rand::rngs::StdRng;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use std::collections::HashSet;
|
|
||||||
mod finum;
|
mod finum;
|
||||||
use finum::FiNum;
|
use finum::FiNum;
|
||||||
|
|
||||||
@@ -61,7 +58,7 @@ struct Trader {
|
|||||||
password: String, // hash(name..salt..password)
|
password: String, // hash(name..salt..password)
|
||||||
id: usize,
|
id: usize,
|
||||||
balances: HashMap<usize,FiNum>, // Maps Currency to Amount
|
balances: HashMap<usize,FiNum>, // Maps Currency to Amount
|
||||||
orders: HashSet<usize>,
|
order_finder: HashMap<usize,(usize,usize)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -92,7 +89,7 @@ impl Trader {
|
|||||||
password: String::from(""),
|
password: String::from(""),
|
||||||
id: id,
|
id: id,
|
||||||
balances: HashMap::new(),
|
balances: HashMap::new(),
|
||||||
orders: HashSet::new(),
|
order_finder: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn add_balance(&mut self, cur:usize, delta:FiNum) {
|
fn add_balance(&mut self, cur:usize, delta:FiNum) {
|
||||||
@@ -114,30 +111,32 @@ struct Order {
|
|||||||
royalty_remain: FiNum, // Based on royalty1
|
royalty_remain: FiNum, // Based on royalty1
|
||||||
commission_remain: FiNum, // Based on commission1
|
commission_remain: FiNum, // Based on commission1
|
||||||
owner: usize,
|
owner: usize,
|
||||||
id: usize,
|
order_id: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RoyaltyTree {
|
struct RoyaltyTree {
|
||||||
tree: Vec<Royalty>,
|
tree: Vec<Royalty>,
|
||||||
next_entry: usize,
|
next_entry: usize,
|
||||||
spare_change: FiNum, // Waiting to be distributed
|
spare_change: FiNum, // Waiting to be distributed
|
||||||
|
order_finder: HashMap<usize,usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Royalty {
|
struct Royalty {
|
||||||
weight: FiNum, // Here and below
|
weight: FiNum, // Here and below
|
||||||
lazy: FiNum, // To be distributed to here and to below based on weights
|
lazy: FiNum, // To be distributed to here and to below based on weights
|
||||||
acc: FiNum, // Accumulated here
|
acc: FiNum, // Accumulated here
|
||||||
|
order_id: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Royalty {
|
impl Royalty {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Royalty { weight:FiNum::zero(), lazy:FiNum::zero(), acc:FiNum::zero() }
|
Royalty { weight:FiNum::zero(), lazy:FiNum::zero(), acc:FiNum::zero(), order_id:0, }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RoyaltyTree {
|
impl RoyaltyTree {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
RoyaltyTree { tree:Vec::new(), next_entry:0, spare_change:FiNum::zero() }
|
RoyaltyTree { tree:Vec::new(), next_entry:0, spare_change:FiNum::zero(), order_finder:HashMap::new() }
|
||||||
}
|
}
|
||||||
fn acc_total(&self) -> FiNum {
|
fn acc_total(&self) -> FiNum {
|
||||||
let mut rval=FiNum::zero();
|
let mut rval=FiNum::zero();
|
||||||
@@ -206,6 +205,12 @@ impl RoyaltyTree {
|
|||||||
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 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn remove_order_id(&mut self, id: usize) {
|
||||||
|
self.order_finder.remove(&id);
|
||||||
|
}
|
||||||
|
fn set_location(&mut self, id: usize, index: usize) {
|
||||||
|
self.order_finder.insert(id,index);
|
||||||
|
}
|
||||||
fn add_weight(&mut self, index: usize, weight: FiNum) {
|
fn add_weight(&mut self, index: usize, weight: FiNum) {
|
||||||
if self.tree.len()>0 {
|
if self.tree.len()>0 {
|
||||||
let mut ff0=self.forefather();
|
let mut ff0=self.forefather();
|
||||||
@@ -250,24 +255,12 @@ impl Dumpable for usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Dumpable for Rc<RefCell<Order>> {
|
|
||||||
fn dump(&self) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl Dumpable for Order {
|
impl Dumpable for Order {
|
||||||
fn dump(&self) {
|
fn dump(&self) {
|
||||||
println!("Giving {}/{} to get {}",self.sell_remain,self.sell_qty,self.buy_qty);
|
println!("Giving {}/{} to get {}",self.sell_remain,self.sell_qty,self.buy_qty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OrderFinder {
|
|
||||||
asset0: usize,
|
|
||||||
asset1: usize,
|
|
||||||
pq_loc: usize,
|
|
||||||
rt_loc: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Market {
|
struct Market {
|
||||||
asset_name2num: HashMap<String,usize>,
|
asset_name2num: HashMap<String,usize>,
|
||||||
@@ -278,7 +271,7 @@ struct Market {
|
|||||||
orders: HashMap<(usize,usize),OrderQueue>,
|
orders: HashMap<(usize,usize),OrderQueue>,
|
||||||
royalties: HashMap<usize,RoyaltyTree>, // Active orders that are accepting asset X. They receive royalties when someone makes an order to sell X
|
royalties: HashMap<usize,RoyaltyTree>, // Active orders that are accepting asset X. They receive royalties when someone makes an order to sell X
|
||||||
royalty_rate: HashMap<usize,FiNum>,
|
royalty_rate: HashMap<usize,FiNum>,
|
||||||
order_finder: HashMap<usize,(usize,usize,usize)>, // To find an order, look in Orders.get(usize,usize) at position usize
|
order_finder: HashMap<usize,(usize,usize)>, // To find an order, look in Orders.get(usize,usize) at position usize
|
||||||
next_order_id: usize,
|
next_order_id: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,8 +362,8 @@ impl Market {
|
|||||||
off.sell_remain, // off.buy_qty*off.sell_remain/off.sell_qty,
|
off.sell_remain, // off.buy_qty*off.sell_remain/off.sell_qty,
|
||||||
(off.buy_qty/off.sell_qty).fmt_recip(),
|
(off.buy_qty/off.sell_qty).fmt_recip(),
|
||||||
self.traders[off.owner as usize].name,
|
self.traders[off.owner as usize].name,
|
||||||
off.id,
|
off.order_id,
|
||||||
self.royalties.get_mut(&ap.1).unwrap().get_royalty(off.rt_loc));
|
"GetRoyalties Code absent");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("Royalties accumulated but not captured:");
|
println!("Royalties accumulated but not captured:");
|
||||||
@@ -475,43 +468,53 @@ impl Market {
|
|||||||
top_order.royalty_remain-=rq2;
|
top_order.royalty_remain-=rq2;
|
||||||
top_order.commission_remain-=cq2;
|
top_order.commission_remain-=cq2;
|
||||||
self.traders[0].add_balance(buy_type,cq2);
|
self.traders[0].add_balance(buy_type,cq2);
|
||||||
self.royalties.entry(buy_type).or_insert(RoyaltyTree::new()).add_royalty(rq2);
|
|
||||||
if elt.sell_remain==0.into() { // deal with pennies stored in royalty_remain and commission_remain
|
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.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.entry(buy_type).or_insert(RoyaltyTree::new()).add_royalty(top_order.royalty_remain);
|
||||||
self.orders.get_mut(&ap).unwrap().pop();
|
self.royalties.get_mut(&sell_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
|
||||||
} else {
|
} else {
|
||||||
top_order.sell_remain-=qty;
|
top_order.sell_remain-=qty;
|
||||||
}
|
}
|
||||||
} else { break; }
|
} else { break; }
|
||||||
}
|
}
|
||||||
|
let mut id=0;
|
||||||
if buy_qty>0.into() {
|
if buy_qty>0.into() {
|
||||||
let ap=(sell_type,buy_type);
|
let ap=(sell_type,buy_type);
|
||||||
if let None=self.orders.get_mut(&ap) { self.orders.insert(ap,OrderQueue::new()); }
|
if let None=self.orders.get_mut(&ap) { self.orders.insert(ap,OrderQueue::new()); }
|
||||||
let bids=self.orders.get_mut(&ap).unwrap();
|
let bids=self.orders.get_mut(&ap).unwrap();
|
||||||
let sell_qty_remain=sell_qty*buy_qty/buy_qty_initial;
|
let sell_qty_remain=sell_qty*buy_qty/buy_qty_initial;
|
||||||
if sell_qty_remain>0.into() {
|
if sell_qty_remain>0.into() { // This block can not fail
|
||||||
self.royalties.entry(sell_type).or_insert(RoyaltyTree::new()).add_royalty(royalty0_qty);
|
// Allocate the id for this new order
|
||||||
let rt=self.royalties.entry(buy_type).or_insert(RoyaltyTree::new());
|
id=self.next_order_id;
|
||||||
let rt_loc=rt.next_entry;
|
|
||||||
rt.add_weight(rt_loc,buy_qty); // Weight should really be the quantity you would be able to immediately transact rather than how much you wish for.
|
|
||||||
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, id:self.next_order_id };
|
|
||||||
new_order_id=self.next_order_id;
|
|
||||||
self.next_order_id+=1;
|
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);
|
||||||
|
|
||||||
|
// Create a new entry in the RoyaltyTree to accumulate for this Order
|
||||||
|
let rt=self.royalties.entry(buy_type).or_insert(RoyaltyTree::new());
|
||||||
|
rt.add_weight(rt.next_entry,buy_qty); // Weight should really be the quantity you would be able to immediately transact rather than how much you wish for.
|
||||||
|
rt.set_location(id,rt.next_entry);
|
||||||
rt.next_entry+=1;
|
rt.next_entry+=1;
|
||||||
let pq_loc=bids.insert(neworder);
|
|
||||||
|
// 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);
|
||||||
|
self.order_finder.insert(id,(sell_type,buy_type));
|
||||||
self.traders[owner].sub_balance(sell_type,sell_qty_remain);
|
self.traders[owner].sub_balance(sell_type,sell_qty_remain);
|
||||||
self.traders[0].add_balance(sell_type,commission0_qty);
|
self.traders[0].add_balance(sell_type,commission0_qty);
|
||||||
self.traders[owner].orders.insert(new_order_id);
|
self.traders[owner].order_finder.insert(id,(sell_type,buy_type));
|
||||||
self.order_finder.insert(new_order_id,OrderFinder { asset0:sell_type, asset1:buy_type, pq_loc: pq_loc, rt_loc: rt_loc });
|
|
||||||
log.push(format!("Moved {} {} ({}) to market",sell_qty_remain,self.number_to_name(sell_type),self.traders[owner].name));
|
log.push(format!("Moved {} {} ({}) to market",sell_qty_remain,self.number_to_name(sell_type),self.traders[owner].name));
|
||||||
} else { new_order_id=0; }
|
}
|
||||||
} else { new_order_id=0; }
|
}
|
||||||
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);
|
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),
|
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));
|
commission_acc,self.number_to_name(sell_type),self.traders[owner].name));
|
||||||
Result::PlacedOrder(new_order_id,log)
|
Result::PlacedOrder(id,log)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,12 +539,14 @@ impl PartialEq for Order {
|
|||||||
|
|
||||||
struct OrderQueue {
|
struct OrderQueue {
|
||||||
v: Vec<Order>,
|
v: Vec<Order>,
|
||||||
|
order_finder: HashMap<usize,usize>, // Maps IDs to locations in v
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OrderQueue {
|
impl OrderQueue {
|
||||||
fn new()->Self {
|
fn new()->Self {
|
||||||
OrderQueue {
|
OrderQueue {
|
||||||
v: Vec::new()
|
v: Vec::new(),
|
||||||
|
order_finder:HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn peek(&mut self) -> &mut Order {
|
fn peek(&mut self) -> &mut Order {
|
||||||
@@ -550,18 +555,19 @@ impl OrderQueue {
|
|||||||
fn empty(&self) -> bool {
|
fn empty(&self) -> bool {
|
||||||
self.v.len()==0
|
self.v.len()==0
|
||||||
}
|
}
|
||||||
fn bubble_up(&mut self, pos: usize) -> usize {
|
fn bubble_up(&mut self, pos: usize) {
|
||||||
if pos>0 {
|
if pos>0 {
|
||||||
let parent=(pos-1)/2;
|
let parent=(pos-1)/2;
|
||||||
if self.v[parent]<self.v[pos] {
|
if self.v[parent]<self.v[pos] {
|
||||||
self.v[parent].pq_loc=pos;
|
self.swap(parent,pos);
|
||||||
self.v[pos].pq_loc=parent;
|
self.bubble_up(parent);
|
||||||
self.v.swap(parent,pos);
|
|
||||||
self.bubble_up(parent)
|
|
||||||
}
|
}
|
||||||
else { pos }
|
|
||||||
}
|
}
|
||||||
else { pos }
|
}
|
||||||
|
fn swap(&mut self, pos0: usize, pos1: usize) {
|
||||||
|
self.order_finder.insert(self.v[pos0].order_id,pos1);
|
||||||
|
self.order_finder.insert(self.v[pos1].order_id,pos0);
|
||||||
|
self.v.swap(pos0,pos1);
|
||||||
}
|
}
|
||||||
fn trickle_down(&mut self, pos: usize) {
|
fn trickle_down(&mut self, pos: usize) {
|
||||||
let mut pivot=pos;
|
let mut pivot=pos;
|
||||||
@@ -573,23 +579,23 @@ impl OrderQueue {
|
|||||||
if self.v[pivot]<self.v[child1] { pivot=child1; }
|
if self.v[pivot]<self.v[child1] { pivot=child1; }
|
||||||
}
|
}
|
||||||
if pivot!=pos {
|
if pivot!=pos {
|
||||||
self.v[pivot].pq_loc=pos;
|
self.swap(pivot,pos);
|
||||||
self.v[pos].pq_loc=pivot;
|
|
||||||
self.v.swap(pivot,pos);
|
|
||||||
self.trickle_down(pivot);
|
self.trickle_down(pivot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn insert(&mut self, mut item: Order) -> usize {
|
fn insert(&mut self, item: Order) {
|
||||||
item.pq_loc=self.v.len();
|
let id=item.order_id;
|
||||||
self.v.push(item);
|
self.v.push(item);
|
||||||
self.bubble_up(self.v.len()-1)
|
self.order_finder.insert(id,self.v.len()-1);
|
||||||
|
self.bubble_up(self.v.len()-1);
|
||||||
}
|
}
|
||||||
fn pop(&mut self) -> Option<Order> {
|
fn pop(&mut self) -> Option<Order> {
|
||||||
if self.v.len()==0 { None }
|
if self.v.len()==0 { None }
|
||||||
else {
|
else {
|
||||||
let end=self.v.len()-1;
|
let end=self.v.len()-1;
|
||||||
self.v.swap(0,end);
|
self.v.swap(0,end);
|
||||||
|
self.order_finder.remove(&self.v[end].order_id);
|
||||||
let rval=self.v.pop();
|
let rval=self.v.pop();
|
||||||
self.trickle_down(0);
|
self.trickle_down(0);
|
||||||
rval
|
rval
|
||||||
|
|||||||
Reference in New Issue
Block a user