Fix orderbook decimals
This commit is contained in:
parent
f45e614765
commit
c838c58ca6
|
@ -15,12 +15,16 @@ use solana_sdk::{
|
||||||
use std::{
|
use std::{
|
||||||
borrow::BorrowMut,
|
borrow::BorrowMut,
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
time::{SystemTime, UNIX_EPOCH}, mem::size_of,
|
mem::size_of,
|
||||||
|
time::{SystemTime, UNIX_EPOCH},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::metrics::MetricU64;
|
use crate::metrics::MetricU64;
|
||||||
use anchor_lang::AccountDeserialize;
|
use anchor_lang::AccountDeserialize;
|
||||||
use mango_v4::{state::{BookSide, OrderTreeType}, serum3_cpi::OrderBookStateHeader};
|
use mango_v4::{
|
||||||
|
serum3_cpi::OrderBookStateHeader,
|
||||||
|
state::{BookSide, OrderTreeType},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum OrderbookSide {
|
pub enum OrderbookSide {
|
||||||
|
@ -40,24 +44,7 @@ impl Serialize for OrderbookSide {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
pub type OrderbookLevel = [f64; 2];
|
||||||
pub struct OrderbookLevel {
|
|
||||||
pub price: f64,
|
|
||||||
pub size: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Serialize for OrderbookLevel {
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: Serializer,
|
|
||||||
{
|
|
||||||
let mut state = serializer.serialize_struct("OrderbookLevel", 2)?;
|
|
||||||
state.serialize_field("price", &self.price)?;
|
|
||||||
state.serialize_field("size", &self.size)?;
|
|
||||||
|
|
||||||
state.end()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct OrderbookUpdate {
|
pub struct OrderbookUpdate {
|
||||||
|
@ -121,12 +108,57 @@ pub struct MarketConfig {
|
||||||
pub asks: Pubkey,
|
pub asks: Pubkey,
|
||||||
pub base_decimals: u8,
|
pub base_decimals: u8,
|
||||||
pub quote_decimals: u8,
|
pub quote_decimals: u8,
|
||||||
|
pub base_lot_size: i64,
|
||||||
|
pub quote_lot_size: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn native_to_ui(native: i64, decimals: u8) -> f64 {
|
pub fn base_lots_to_ui(native: i64, base_decimals: u8, base_lot_size: i64) -> f64 {
|
||||||
native as f64 / (10u64.pow(decimals.into())) as f64
|
let decimals: u32 = 3;
|
||||||
|
let res = native as f64 / (10i64.pow(decimals.into()) as f64);
|
||||||
|
//info!("res {} native {} base_d {} base ls {}", res, native, base_decimals, base_lot_size);
|
||||||
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn base_lots_to_ui_perp(native: i64, base_decimals: u8, base_lot_size: i64) -> f64 {
|
||||||
|
let decimals: u32 = 4;
|
||||||
|
let res = native as f64 / (10i64.pow(decimals.into()) as f64);
|
||||||
|
//info!("res {} native {} base_d {} base ls {}", res, native, base_decimals, base_lot_size);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn price_lots_to_ui(
|
||||||
|
native: i64,
|
||||||
|
base_decimals: u8,
|
||||||
|
quote_decimals: u8,
|
||||||
|
) -> f64 {
|
||||||
|
let decimals = base_decimals - quote_decimals;
|
||||||
|
// let res = native as f64
|
||||||
|
// * ((10u64.pow(decimals.into()) * quote_lot_size as u64) as f64 / base_lot_size as f64)
|
||||||
|
// as f64;
|
||||||
|
let res = native as f64
|
||||||
|
/ (10u64.pow(decimals.into()))
|
||||||
|
as f64;
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn price_lots_to_ui_perp(
|
||||||
|
native: i64,
|
||||||
|
base_decimals: u8,
|
||||||
|
quote_decimals: u8,
|
||||||
|
base_lot_size: i64,
|
||||||
|
quote_lot_size: i64,
|
||||||
|
) -> f64 {
|
||||||
|
let decimals = base_decimals - quote_decimals;
|
||||||
|
let res = native as f64
|
||||||
|
* ((10u64.pow(decimals.into()) * quote_lot_size as u64) as f64 / base_lot_size as f64)
|
||||||
|
as f64;
|
||||||
|
// let res = native as f64
|
||||||
|
// / (10u64.pow(decimals.into()))
|
||||||
|
// as f64;
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fn publish_changes(
|
fn publish_changes(
|
||||||
slot: u64,
|
slot: u64,
|
||||||
write_version: u64,
|
write_version: u64,
|
||||||
|
@ -143,14 +175,12 @@ fn publish_changes(
|
||||||
for previous_order in previous_bookside.iter() {
|
for previous_order in previous_bookside.iter() {
|
||||||
let peer = current_bookside
|
let peer = current_bookside
|
||||||
.iter()
|
.iter()
|
||||||
.find(|level| previous_order.price == level.price);
|
.find(|level| previous_order[0] == level[0]);
|
||||||
|
|
||||||
match peer {
|
match peer {
|
||||||
None => {
|
None => {
|
||||||
update.push(OrderbookLevel {
|
info!("removed level {}", previous_order[0]);
|
||||||
price: previous_order.price,
|
update.push([previous_order[0], 0f64]);
|
||||||
size: 0f64,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
_ => continue,
|
_ => continue,
|
||||||
}
|
}
|
||||||
|
@ -160,21 +190,18 @@ fn publish_changes(
|
||||||
for current_order in current_bookside {
|
for current_order in current_bookside {
|
||||||
let peer = previous_bookside
|
let peer = previous_bookside
|
||||||
.iter()
|
.iter()
|
||||||
.find(|item| item.price == current_order.price);
|
.find(|item| item[0] == current_order[0]);
|
||||||
|
|
||||||
match peer {
|
match peer {
|
||||||
Some(previous_order) => {
|
Some(previous_order) => {
|
||||||
if previous_order.size == current_order.size {
|
if previous_order[1] == current_order[1] {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
debug!(
|
info!("size changed {} -> {}", previous_order[1], current_order[1]);
|
||||||
"size changed {} -> {}",
|
|
||||||
previous_order.size, current_order.size
|
|
||||||
);
|
|
||||||
update.push(current_order.clone());
|
update.push(current_order.clone());
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
debug!("new level {},{}", current_order.price, current_order.size);
|
info!("new level {},{}", current_order[0], current_order[1]);
|
||||||
update.push(current_order.clone())
|
update.push(current_order.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,14 +259,12 @@ fn publish_changes_serum(
|
||||||
for previous_order in previous_bookside.iter() {
|
for previous_order in previous_bookside.iter() {
|
||||||
let peer = current_bookside
|
let peer = current_bookside
|
||||||
.iter()
|
.iter()
|
||||||
.find(|level| previous_order.price == level.price);
|
.find(|level| previous_order[0] == level[0]);
|
||||||
|
|
||||||
match peer {
|
match peer {
|
||||||
None => {
|
None => {
|
||||||
update.push(OrderbookLevel {
|
info!("removed level s {}", previous_order[0]);
|
||||||
price: previous_order.price,
|
update.push([previous_order[0], 0f64]);
|
||||||
size: 0f64,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
_ => continue,
|
_ => continue,
|
||||||
}
|
}
|
||||||
|
@ -249,21 +274,18 @@ fn publish_changes_serum(
|
||||||
for current_order in current_bookside {
|
for current_order in current_bookside {
|
||||||
let peer = previous_bookside
|
let peer = previous_bookside
|
||||||
.iter()
|
.iter()
|
||||||
.find(|item| item.price == current_order.price);
|
.find(|item| item[0] == current_order[0]);
|
||||||
|
|
||||||
match peer {
|
match peer {
|
||||||
Some(previous_order) => {
|
Some(previous_order) => {
|
||||||
if previous_order.size == current_order.size {
|
if previous_order[1] == current_order[1] {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
debug!(
|
info!("size changed {} -> {}", previous_order[1], current_order[1]);
|
||||||
"size changed {} -> {}",
|
|
||||||
previous_order.size, current_order.size
|
|
||||||
);
|
|
||||||
update.push(current_order.clone());
|
update.push(current_order.clone());
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
debug!("new level {},{}", current_order.price, current_order.size);
|
info!("new level {},{}", current_order[0], current_order[1]);
|
||||||
update.push(current_order.clone())
|
update.push(current_order.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -412,14 +434,26 @@ pub async fn init(
|
||||||
.map(|item| (item.node.price_data() as i64, item.node.quantity))
|
.map(|item| (item.node.price_data() as i64, item.node.quantity))
|
||||||
.group_by(|(price, _)| *price)
|
.group_by(|(price, _)| *price)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(price, group)| OrderbookLevel {
|
.map(|(price, group)| {
|
||||||
price: native_to_ui(price, mkt.1.quote_decimals),
|
[
|
||||||
size: native_to_ui(group
|
price_lots_to_ui_perp(
|
||||||
.map(|(_, quantity)| quantity)
|
price,
|
||||||
.fold(0, |acc, x| acc + x), mkt.1.base_decimals),
|
mkt.1.base_decimals,
|
||||||
|
mkt.1.quote_decimals,
|
||||||
|
mkt.1.base_lot_size,
|
||||||
|
mkt.1.quote_lot_size,
|
||||||
|
),
|
||||||
|
base_lots_to_ui_perp(
|
||||||
|
group
|
||||||
|
.map(|(_, quantity)| quantity)
|
||||||
|
.fold(0, |acc, x| acc + x),
|
||||||
|
mkt.1.base_decimals,
|
||||||
|
mkt.1.base_lot_size,
|
||||||
|
),
|
||||||
|
]
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let other_bookside = bookside_cache.get(&other_side_pk.to_string());
|
let other_bookside = bookside_cache.get(&other_side_pk.to_string());
|
||||||
|
|
||||||
match bookside_cache.get(&side_pk_string) {
|
match bookside_cache.get(&side_pk_string) {
|
||||||
|
@ -471,14 +505,26 @@ pub async fn init(
|
||||||
|
|
||||||
let bookside: Vec<OrderbookLevel> = slab
|
let bookside: Vec<OrderbookLevel> = slab
|
||||||
.iter(side == 0)
|
.iter(side == 0)
|
||||||
.map(|item| (u64::from(item.price()) as i64, item.quantity() as i64))
|
.map(|item| {
|
||||||
|
(u64::from(item.price()) as i64, item.quantity() as i64)
|
||||||
|
})
|
||||||
.group_by(|(price, _)| *price)
|
.group_by(|(price, _)| *price)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(price, group)| OrderbookLevel {
|
.map(|(price, group)| {
|
||||||
price: native_to_ui(price, mkt.1.quote_decimals),
|
[
|
||||||
size: native_to_ui(group
|
price_lots_to_ui(
|
||||||
.map(|(_, quantity)| quantity)
|
price,
|
||||||
.fold(0, |acc, x| acc + x), mkt.1.base_decimals),
|
mkt.1.base_decimals,
|
||||||
|
mkt.1.quote_decimals,
|
||||||
|
),
|
||||||
|
base_lots_to_ui(
|
||||||
|
group
|
||||||
|
.map(|(_, quantity)| quantity)
|
||||||
|
.fold(0, |acc, x| acc + x),
|
||||||
|
mkt.1.base_decimals,
|
||||||
|
mkt.1.base_lot_size,
|
||||||
|
),
|
||||||
|
]
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -504,10 +550,7 @@ pub async fn init(
|
||||||
_ => info!("bookside_cache could not find {}", side_pk_string),
|
_ => info!("bookside_cache could not find {}", side_pk_string),
|
||||||
}
|
}
|
||||||
|
|
||||||
serum_bookside_cache.insert(
|
serum_bookside_cache.insert(side_pk_string.clone(), bookside);
|
||||||
side_pk_string.clone(),
|
|
||||||
bookside,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Err(_) => info!("chain_cache could not find {}", side_pk),
|
Err(_) => info!("chain_cache could not find {}", side_pk),
|
||||||
}
|
}
|
||||||
|
|
|
@ -307,6 +307,8 @@ async fn main() -> anyhow::Result<()> {
|
||||||
asks: context.market.asks,
|
asks: context.market.asks,
|
||||||
base_decimals: context.market.base_decimals,
|
base_decimals: context.market.base_decimals,
|
||||||
quote_decimals,
|
quote_decimals,
|
||||||
|
base_lot_size: context.market.base_lot_size,
|
||||||
|
quote_lot_size: context.market.quote_lot_size,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -325,13 +327,15 @@ async fn main() -> anyhow::Result<()> {
|
||||||
None => panic!("token not found for market") // todo: default to 6 for usdc?
|
None => panic!("token not found for market") // todo: default to 6 for usdc?
|
||||||
};
|
};
|
||||||
(
|
(
|
||||||
context.address,
|
context.market.serum_market_external,
|
||||||
MarketConfig {
|
MarketConfig {
|
||||||
name: context.market.name().to_owned(),
|
name: context.market.name().to_owned(),
|
||||||
bids: context.bids,
|
bids: context.bids,
|
||||||
asks: context.asks,
|
asks: context.asks,
|
||||||
base_decimals,
|
base_decimals,
|
||||||
quote_decimals,
|
quote_decimals,
|
||||||
|
base_lot_size: context.pc_lot_size as i64,
|
||||||
|
quote_lot_size: context.coin_lot_size as i64,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue