|
|
@ -13,22 +13,33 @@ use xtra_productivity::xtra_productivity; |
|
|
|
|
|
|
|
pub struct Actor { |
|
|
|
tx: Tx, |
|
|
|
state: State, |
|
|
|
} |
|
|
|
|
|
|
|
pub struct Feeds { |
|
|
|
pub quote: watch::Receiver<Quote>, |
|
|
|
pub order: watch::Receiver<Option<CfdOrder>>, |
|
|
|
pub connected_takers: watch::Receiver<Vec<Identity>>, |
|
|
|
// TODO: Convert items below here into projections
|
|
|
|
pub cfds: watch::Receiver<Vec<ModelCfd>>, |
|
|
|
pub settlements: watch::Receiver<UpdateCfdProposals>, |
|
|
|
pub cfds: watch::Receiver<Vec<Cfd>>, |
|
|
|
} |
|
|
|
|
|
|
|
impl Actor { |
|
|
|
pub fn new(init_cfds: Vec<ModelCfd>, init_quote: bitmex_price_feed::Quote) -> (Self, Feeds) { |
|
|
|
let (tx_cfds, rx_cfds) = watch::channel(init_cfds); |
|
|
|
pub fn new( |
|
|
|
role: Role, |
|
|
|
network: Network, |
|
|
|
init_cfds: Vec<ModelCfd>, |
|
|
|
init_quote: bitmex_price_feed::Quote, |
|
|
|
) -> (Self, Feeds) { |
|
|
|
let state = State { |
|
|
|
role, |
|
|
|
network, |
|
|
|
cfds: init_cfds, |
|
|
|
proposals: HashMap::new(), |
|
|
|
quote: init_quote.clone(), |
|
|
|
}; |
|
|
|
|
|
|
|
let (tx_cfds, rx_cfds) = watch::channel(state.to_cfds()); |
|
|
|
let (tx_order, rx_order) = watch::channel(None); |
|
|
|
let (tx_update_cfd_feed, rx_update_cfd_feed) = watch::channel(HashMap::new()); |
|
|
|
let (tx_quote, rx_quote) = watch::channel(init_quote.into()); |
|
|
|
let (tx_connected_takers, rx_connected_takers) = watch::channel(Vec::new()); |
|
|
|
|
|
|
@ -38,15 +49,14 @@ impl Actor { |
|
|
|
cfds: tx_cfds, |
|
|
|
order: tx_order, |
|
|
|
quote: tx_quote, |
|
|
|
settlements: tx_update_cfd_feed, |
|
|
|
connected_takers: tx_connected_takers, |
|
|
|
}, |
|
|
|
state, |
|
|
|
}, |
|
|
|
Feeds { |
|
|
|
cfds: rx_cfds, |
|
|
|
order: rx_order, |
|
|
|
quote: rx_quote, |
|
|
|
settlements: rx_update_cfd_feed, |
|
|
|
connected_takers: rx_connected_takers, |
|
|
|
}, |
|
|
|
) |
|
|
@ -55,15 +65,49 @@ impl Actor { |
|
|
|
|
|
|
|
/// Internal struct to keep all the senders around in one place
|
|
|
|
struct Tx { |
|
|
|
pub cfds: watch::Sender<Vec<ModelCfd>>, |
|
|
|
pub cfds: watch::Sender<Vec<Cfd>>, |
|
|
|
pub order: watch::Sender<Option<CfdOrder>>, |
|
|
|
pub quote: watch::Sender<Quote>, |
|
|
|
pub settlements: watch::Sender<UpdateCfdProposals>, |
|
|
|
// TODO: Use this channel to communicate maker status as well with generic
|
|
|
|
// ID of connected counterparties
|
|
|
|
pub connected_takers: watch::Sender<Vec<Identity>>, |
|
|
|
} |
|
|
|
|
|
|
|
/// Internal struct to keep state in one place
|
|
|
|
struct State { |
|
|
|
role: Role, |
|
|
|
network: Network, |
|
|
|
quote: bitmex_price_feed::Quote, |
|
|
|
proposals: UpdateCfdProposals, |
|
|
|
cfds: Vec<ModelCfd>, |
|
|
|
} |
|
|
|
|
|
|
|
impl State { |
|
|
|
pub fn to_cfds(&self) -> Vec<Cfd> { |
|
|
|
// FIXME: starting with the intermediate struct, only temporarily
|
|
|
|
let temp = CfdsWithAuxData::new( |
|
|
|
self.cfds.clone(), |
|
|
|
self.quote.clone(), |
|
|
|
self.proposals.clone(), |
|
|
|
self.role, |
|
|
|
self.network, |
|
|
|
); |
|
|
|
temp.into() |
|
|
|
} |
|
|
|
|
|
|
|
pub fn update_proposals(&mut self, proposals: UpdateCfdProposals) { |
|
|
|
let _ = std::mem::replace(&mut self.proposals, proposals); |
|
|
|
} |
|
|
|
|
|
|
|
pub fn update_quote(&mut self, quote: bitmex_price_feed::Quote) { |
|
|
|
let _ = std::mem::replace(&mut self.quote, quote); |
|
|
|
} |
|
|
|
|
|
|
|
pub fn update_cfds(&mut self, cfds: Vec<ModelCfd>) { |
|
|
|
let _ = std::mem::replace(&mut self.cfds, cfds); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
pub struct Update<T>(pub T); |
|
|
|
|
|
|
|
#[xtra_productivity] |
|
|
@ -72,13 +116,18 @@ impl Actor { |
|
|
|
let _ = self.tx.order.send(msg.0.map(|x| x.into())); |
|
|
|
} |
|
|
|
fn handle(&mut self, msg: Update<bitmex_price_feed::Quote>) { |
|
|
|
let _ = self.tx.quote.send(msg.0.into()); |
|
|
|
let quote = msg.0; |
|
|
|
self.state.update_quote(quote.clone()); |
|
|
|
let _ = self.tx.quote.send(quote.into()); |
|
|
|
let _ = self.tx.cfds.send(self.state.to_cfds()); |
|
|
|
} |
|
|
|
fn handle(&mut self, msg: Update<Vec<ModelCfd>>) { |
|
|
|
let _ = self.tx.cfds.send(msg.0); |
|
|
|
self.state.update_cfds(msg.0); |
|
|
|
let _ = self.tx.cfds.send(self.state.to_cfds()); |
|
|
|
} |
|
|
|
fn handle(&mut self, msg: Update<UpdateCfdProposals>) { |
|
|
|
let _ = self.tx.settlements.send(msg.0); |
|
|
|
self.state.update_proposals(msg.0); |
|
|
|
let _ = self.tx.cfds.send(self.state.to_cfds()); |
|
|
|
} |
|
|
|
fn handle(&mut self, msg: Update<Vec<model::Identity>>) { |
|
|
|
let _ = self |
|
|
@ -396,8 +445,8 @@ pub struct Cfd { |
|
|
|
pub expiry_timestamp: OffsetDateTime, |
|
|
|
} |
|
|
|
|
|
|
|
impl From<&CfdsWithAuxData> for Vec<Cfd> { |
|
|
|
fn from(input: &CfdsWithAuxData) -> Self { |
|
|
|
impl From<CfdsWithAuxData> for Vec<Cfd> { |
|
|
|
fn from(input: CfdsWithAuxData) -> Self { |
|
|
|
let current_price = input.current_price; |
|
|
|
let network = input.network; |
|
|
|
|
|
|
@ -460,22 +509,19 @@ pub struct CfdsWithAuxData { |
|
|
|
|
|
|
|
impl CfdsWithAuxData { |
|
|
|
pub fn new( |
|
|
|
rx_cfds: &watch::Receiver<Vec<model::cfd::Cfd>>, |
|
|
|
rx_quote: &watch::Receiver<Quote>, |
|
|
|
rx_updates: &watch::Receiver<UpdateCfdProposals>, |
|
|
|
cfds: Vec<model::cfd::Cfd>, |
|
|
|
quote: bitmex_price_feed::Quote, |
|
|
|
pending_proposals: UpdateCfdProposals, |
|
|
|
role: Role, |
|
|
|
network: Network, |
|
|
|
) -> Self { |
|
|
|
let quote: bitmex_price_feed::Quote = rx_quote.borrow().clone().into(); |
|
|
|
let current_price = match role { |
|
|
|
Role::Maker => quote.for_maker(), |
|
|
|
Role::Taker => quote.for_taker(), |
|
|
|
}; |
|
|
|
|
|
|
|
let pending_proposals = rx_updates.borrow().clone(); |
|
|
|
|
|
|
|
CfdsWithAuxData { |
|
|
|
cfds: rx_cfds.borrow().clone(), |
|
|
|
cfds, |
|
|
|
current_price, |
|
|
|
pending_proposals, |
|
|
|
network, |
|
|
|