Path Finding and arbitrage detection works. Need to print out when detecting arbitrage.

This commit is contained in:
2025-02-04 10:59:39 -05:00
parent 8fa172da17
commit 4a334d4f66
4 changed files with 1103 additions and 100137 deletions

101122
1.log

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,18 @@
AT Teppy ; addtrader Teppy AT Teppy
AT Luni ; addtrader Luni AT Luni
AT Hamza ; addtrader Hamza AT Hamza
AA USD ; addasset USD AT UncleSam
AA BTC ; addasset BTC NOP Error: Could not find asset BTC
SR 0 51EB851 28F5C28 7AE147A 28F5C28 ; setroyalty USD 0.02 0.01 0.03 0.01 NOP Error: Could not find asset ETH
SR 1 51EB851 28F5C28 7AE147A 28F5C28 ; setroyalty BTC 0.02 0.01 0.03 0.01 AA USD
AF 1 1 500000000 ; addfunds Teppy 5 BTC AA BTC
AF 2 0 186A000000000 ; addfunds Luni 100000 USD AA ETH
AF 3 0 186A000000000 ; addfunds Hamza 100000 USD AA SOL
OR 1 1 200000000 0 186A000000000 ; [login Teppy] order 2 BTC 100000 USD AF 1 1 A00000000
NOP OR 2 0 753000000000 1 80000000 ; [login Luni] order 30000 USD 0.5 BTC AF 2 2 3200000000
NOP OR 2 0 4E2000000000 1 80000000 ; [login Luni] order 20000 USD 0.5 BTC AF 3 3 FA00000000
NOP OR 2 0 55F000000000 1 80000000 ; [login Luni] order 22000 USD 0.5 BTC AF 4 0 F424000000000
NOP OR 2 1 40000000 0 35B600000000 ; [login Luni] order 0.25 BTC 13750 USD OR 1 1 100000000 2 400000000
OR 2 2 100000000 3 400000000
OR 3 3 100000000 0 FA00000000
OR 1 1 100000000 3 1900000000

View File

@@ -24,6 +24,9 @@ impl FiNum {
pub fn one() -> Self { pub fn one() -> Self {
FiNum(1u64<<32) FiNum(1u64<<32)
} }
pub fn infinity() -> Self {
FiNum(u64::MAX)
}
pub fn is_tiny(self) -> bool { pub fn is_tiny(self) -> bool {
self.0>0u64 && self.0<=1u64 self.0>0u64 && self.0<=1u64
} }

View File

@@ -36,6 +36,13 @@
// //
//
// Thoughts on cheapest-path algorithm:
// Create a square matrix of costs from each asset to each asset. Some of the entries will be infinity. The goal is to lower the entries.
// In each cell, store not just the cost, but the path and path capacity.
// Starting with the source asset, see if visiting each other asset lowers the cost to get there. If it does, replace that asset's cost with the new cost and path.
//
#![allow(unsafe_code)] #![allow(unsafe_code)]
#![allow(unused_variables)] #![allow(unused_variables)]
@@ -48,6 +55,7 @@ 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::cmp::min;
use rand::prelude::*; use rand::prelude::*;
use rand::rngs::StdRng; use rand::rngs::StdRng;
use std::time::Instant; use std::time::Instant;
@@ -728,7 +736,68 @@ impl Market {
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(id,log) Result::PlacedOrder(id,log)
} }
fn path_cost(&self, src: usize, dest: usize, depth_left: usize) -> TradePath {
let mut cheapest=vec![TradePath::new();self.assets.len()];
cheapest[src].cost=FiNum::new_i32(1);
cheapest[src].path[0]=src;
cheapest[src].len=1;
for i in 0..6 {
let mut progress=false;
for ass0 in 0..self.assets.len() {
for ass1 in 0..self.assets.len() {
if true || ass0!=ass1 {
if let Some(topq)=self.orders.get(&(ass1,ass0)) {
if let Some(top)=topq.peekn() {
println!("There is a direct path from {} to {} with a cost of {} {}",
self.number_to_name(ass0),self.number_to_name(ass1),top.buy_qty/top.sell_qty,self.number_to_name(ass1));
let candidate=cheapest[ass0].cost*top.buy_qty/top.sell_qty;
if candidate<cheapest[ass1].cost {
// Extend cheapest[ass1]
println!("Extending Length {} {} because {} < {}",cheapest[ass0].len,self.number_to_name(ass1),candidate,cheapest[ass1].cost);
cheapest[ass1]=cheapest[ass0];
let ext=&mut cheapest[ass1];
let arbitrage=ext.path.contains(&ass1);
ext.path[ext.len]=ass1;
ext.len+=1;
ext.cost=candidate;
ext.cap=min(ext.cap,ext.cost*top.sell_remain);
progress=true;
if arbitrage {
return ext.clone();
}
}
}
}
}
}
}
if !progress { println!("Definitely found the cheapest path."); break; }
}
for ass in 0..self.assets.len() { println!("Cheapest path from {} to {} is {}",self.number_to_name(src),self.number_to_name(ass),cheapest[ass].cost); }
cheapest[dest].clone()
} }
}
#[derive(Copy,Clone)]
struct TradePath {
cost: FiNum,
path: [ usize; 600],
len: usize,
cap: FiNum,
arbitrage: bool,
}
impl TradePath {
fn new() -> Self { TradePath {
cost: FiNum::infinity(),
path: [0; 600],
len: 0,
cap: FiNum::infinity(),
arbitrage: false,
} }
}
impl PartialOrd for Order { impl PartialOrd for Order {
fn partial_cmp(&self, other:&Self) -> Option<Ordering> { fn partial_cmp(&self, other:&Self) -> Option<Ordering> {
@@ -764,6 +833,9 @@ impl OrderQueue {
fn peek(&mut self) -> &mut Order { fn peek(&mut self) -> &mut Order {
self.v.first_mut().unwrap() self.v.first_mut().unwrap()
} }
fn peekn(&self) -> Option<&Order> {
self.v.first()
}
fn empty(&self) -> bool { fn empty(&self) -> bool {
self.v.len()==0 self.v.len()==0
} }
@@ -1252,6 +1324,16 @@ fn interactive(m: &mut Market, mut out: Option<File>) {
let cmd:Command=match tokens.as_slice() { let cmd:Command=match tokens.as_slice() {
["dump"] => { m.dump(); Command::None }, ["dump"] => { m.dump(); Command::None },
["sanity"] => { m.sanity_check(); Command::None }, ["sanity"] => { m.sanity_check(); Command::None },
["path",src,dest] => {
let cur0=*m.name_to_number(src).unwrap();
let cur1=*m.name_to_number(dest).unwrap();
let path=m.path_cost(cur0,cur1,6);
let mut str=format!("Cost: {} Cap: {}",path.cost,path.cap);
if path.len>0 { str=format!("{} {}",str,m.number_to_name(path.path[0])) }
for i in 1..path.len { str=format!("{}->{}",str,m.number_to_name(path.path[i])) }
println!("{}",str);
Command::None
},
["randomorder"] => { println!("Random OrderID: {:?}",m.random_order_id()); Command::None } ["randomorder"] => { println!("Random OrderID: {:?}",m.random_order_id()); Command::None }
["login", username] => { ["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) } 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) }