rust #10
@ -33,21 +33,21 @@ impl BfxBot {
|
||||
tick_duration: Duration,
|
||||
) -> Self {
|
||||
let clients: Vec<_> = exchanges.iter().map(|x| Client::new(x)).collect();
|
||||
let pairs: Vec<_> = trading_symbols
|
||||
.iter()
|
||||
.map(|x| SymbolPair::new(quote.clone(), x.clone()))
|
||||
.collect();
|
||||
|
||||
let mut pos_managers = Vec::new();
|
||||
let mut order_managers = Vec::new();
|
||||
let mut pair_statuses = Vec::new();
|
||||
|
||||
for c in clients {
|
||||
pos_managers.push(PositionManager::new(c.clone()));
|
||||
order_managers.push(OrderManager::new(c.clone()));
|
||||
pair_statuses.extend(
|
||||
trading_symbols
|
||||
.iter()
|
||||
.map(|x| SymbolPair::new(quote.clone(), x.clone()))
|
||||
.map(|x| PriceManager::new(x, c.clone()))
|
||||
.collect::<Vec<PriceManager>>(),
|
||||
)
|
||||
for p in &pairs {
|
||||
pos_managers.push(PositionManager::new(p.clone(), c.clone()));
|
||||
order_managers.push(OrderManager::new(p.clone(), c.clone()));
|
||||
pair_statuses.push(PriceManager::new(p.clone(), c.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
BfxBot {
|
||||
@ -79,10 +79,23 @@ impl BfxBot {
|
||||
|
||||
async fn update_managers(&mut self) -> Result<(), BoxError> {
|
||||
self.update_price_managers().await?;
|
||||
self.update_position_managers().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update_position_managers(&mut self) -> Result<Option<Vec<Event>>, BoxError> {
|
||||
for mgr in &mut self.pos_managers {
|
||||
let tick = self.ticker.current_tick();
|
||||
|
||||
mgr.update(tick).await?;
|
||||
|
||||
println!("{:?}", mgr);
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
async fn update_price_managers(&mut self) -> Result<Option<Vec<Event>>, BoxError> {
|
||||
let futures: Vec<_> = self
|
||||
.price_managers
|
||||
|
@ -45,7 +45,10 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn active_positions(&self, pair: &SymbolPair) -> Result<Vec<Position>, BoxError> {
|
||||
pub async fn active_positions(
|
||||
&self,
|
||||
pair: &SymbolPair,
|
||||
) -> Result<Option<Vec<Position>>, BoxError> {
|
||||
self.inner.active_positions(pair).await
|
||||
}
|
||||
|
||||
@ -70,7 +73,7 @@ impl Client {
|
||||
|
||||
#[async_trait]
|
||||
pub trait Connector: Send + Sync {
|
||||
async fn active_positions(&self, pair: &SymbolPair) -> Result<Vec<Position>, BoxError>;
|
||||
async fn active_positions(&self, pair: &SymbolPair) -> Result<Option<Vec<Position>>, BoxError>;
|
||||
async fn current_prices(&self, pair: &SymbolPair) -> Result<TradingPairTicker, BoxError>;
|
||||
async fn active_orders(&self, pair: &SymbolPair) -> Result<Vec<Order>, BoxError>;
|
||||
async fn submit_order(
|
||||
@ -123,14 +126,20 @@ impl BitfinexConnector {
|
||||
|
||||
#[async_trait]
|
||||
impl Connector for BitfinexConnector {
|
||||
async fn active_positions(&self, pair: &SymbolPair) -> Result<Vec<Position>, BoxError> {
|
||||
async fn active_positions(&self, pair: &SymbolPair) -> Result<Option<Vec<Position>>, BoxError> {
|
||||
let active_positions = self.bfx.positions.active_positions().await?;
|
||||
|
||||
Ok(active_positions
|
||||
let positions: Vec<_> = active_positions
|
||||
.into_iter()
|
||||
.filter_map(|x| x.try_into().ok())
|
||||
.filter(|x: &Position| x.pair() == pair)
|
||||
.collect())
|
||||
.collect();
|
||||
|
||||
if positions.is_empty() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(positions))
|
||||
}
|
||||
}
|
||||
|
||||
async fn current_prices(&self, pair: &SymbolPair) -> Result<TradingPairTicker, BoxError> {
|
||||
|
@ -147,18 +147,21 @@ impl PriceEntry {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PositionManager {
|
||||
queue: VecDeque<Position>,
|
||||
open_positions: Vec<Position>,
|
||||
pair: SymbolPair,
|
||||
positions_history: HashMap<u64, Position>,
|
||||
active_position: Option<Position>,
|
||||
client: Client,
|
||||
strategy: Option<Box<dyn PositionStrategy>>,
|
||||
}
|
||||
|
||||
impl PositionManager {
|
||||
pub fn new(client: Client) -> Self {
|
||||
pub fn new(pair: SymbolPair, client: Client) -> Self {
|
||||
PositionManager {
|
||||
queue: VecDeque::new(),
|
||||
open_positions: Vec::new(),
|
||||
pair,
|
||||
positions_history: HashMap::new(),
|
||||
active_position: None,
|
||||
client,
|
||||
strategy: None,
|
||||
}
|
||||
@ -169,21 +172,61 @@ impl PositionManager {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn update(&self) -> Option<Vec<Event>> {
|
||||
unimplemented!()
|
||||
pub async fn update(&mut self, tick: u64) -> Result<Option<Vec<Event>>, BoxError> {
|
||||
let mut opt_active_positions = self.client.active_positions(&self.pair).await?;
|
||||
let mut events = vec![];
|
||||
|
||||
if opt_active_positions.is_none() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// we assume there is only ONE active position per pair
|
||||
match opt_active_positions
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.filter(|x| x.pair() == &self.pair)
|
||||
.next()
|
||||
{
|
||||
Some(position) => {
|
||||
// applying strategy to position
|
||||
let active_position = {
|
||||
match &self.strategy {
|
||||
Some(strategy) => {
|
||||
let (pos, strategy_events, _) = strategy.on_new_tick(&position, &self);
|
||||
|
||||
events.extend(strategy_events);
|
||||
pos
|
||||
}
|
||||
None => position,
|
||||
}
|
||||
};
|
||||
|
||||
self.positions_history.insert(tick, active_position.clone());
|
||||
self.active_position = Some(active_position);
|
||||
}
|
||||
None => {
|
||||
self.active_position = None;
|
||||
}
|
||||
}
|
||||
|
||||
if events.is_empty() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(events))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OrderManager {
|
||||
queue: VecDeque<Order>,
|
||||
pair: SymbolPair,
|
||||
open_orders: Vec<Order>,
|
||||
client: Client,
|
||||
}
|
||||
|
||||
impl OrderManager {
|
||||
pub fn new(client: Client) -> Self {
|
||||
pub fn new(pair: SymbolPair, client: Client) -> Self {
|
||||
OrderManager {
|
||||
queue: VecDeque::new(),
|
||||
pair,
|
||||
open_orders: Vec::new(),
|
||||
client,
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ pub enum OrderKind {
|
||||
* Positions
|
||||
***************/
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Position {
|
||||
pair: SymbolPair,
|
||||
state: PositionState,
|
||||
|
@ -1,18 +1,25 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::events::{Event, EventKind, EventMetadata, SignalKind};
|
||||
use crate::managers::PriceManager;
|
||||
use crate::managers::{PositionManager, PriceManager};
|
||||
use crate::models::{Position, PositionProfitState};
|
||||
use dyn_clone::DynClone;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
|
||||
pub trait PositionStrategy: DynClone {
|
||||
fn on_new_tick(
|
||||
&self,
|
||||
position: &Position,
|
||||
status: &PriceManager,
|
||||
manager: &PositionManager,
|
||||
) -> (Position, Vec<Event>, Vec<SignalKind>);
|
||||
}
|
||||
|
||||
impl Debug for dyn PositionStrategy {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "PositionStrategy")
|
||||
}
|
||||
}
|
||||
|
||||
// #[derive(Clone, Debug)]
|
||||
// pub struct TrailingStop {
|
||||
// stop_percentages: HashMap<u64, f64>,
|
||||
|
Loading…
Reference in New Issue
Block a user