rust #10
@ -4,7 +4,7 @@ use std::ops::Neg;
|
||||
use bitfinex::ticker::TradingPairTicker;
|
||||
use futures_util::stream::FuturesUnordered;
|
||||
use futures_util::StreamExt;
|
||||
use log::{debug, error};
|
||||
use log::{debug, error, info};
|
||||
use tokio::signal::unix::Signal;
|
||||
use tokio::sync::mpsc::channel;
|
||||
use tokio::sync::mpsc::{Receiver, Sender};
|
||||
@ -16,6 +16,8 @@ use crate::models::{ExecutedOrder, OrderForm, OrderKind, Position, PriceTicker};
|
||||
use crate::strategy::{FastOrderStrategy, OrderStrategy, PositionStrategy, TrailingStop};
|
||||
use crate::BoxError;
|
||||
|
||||
type OptionUpdate = (Option<Vec<Event>>, Option<Vec<SignalKind>>);
|
||||
|
||||
pub struct EventManager {
|
||||
events: Vec<Event>,
|
||||
}
|
||||
@ -226,10 +228,8 @@ impl PositionManager {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub async fn update(
|
||||
&mut self,
|
||||
tick: u64,
|
||||
) -> Result<(Option<Vec<Event>>, Option<OrderForm>), BoxError> {
|
||||
|
||||
pub async fn update(&mut self, tick: u64) -> Result<OptionUpdate, BoxError> {
|
||||
let opt_active_positions = self.client.active_positions(&self.pair).await?;
|
||||
let mut events = vec![];
|
||||
|
||||
@ -265,7 +265,7 @@ impl PositionManager {
|
||||
}
|
||||
};
|
||||
|
||||
Ok(((events.is_empty().then_some(events)), None))
|
||||
Ok((None, None))
|
||||
}
|
||||
|
||||
pub fn position_previous_tick(&self, id: u64, tick: Option<u64>) -> Option<&Position> {
|
||||
@ -369,19 +369,26 @@ impl OrderManager {
|
||||
pub async fn close_position(&mut self, position: &Position) -> Result<(), BoxError> {
|
||||
let open_order = self.tracked_positions.get(&position.id());
|
||||
|
||||
info!("Closing position {}", position.id());
|
||||
|
||||
// checking if the position has an open order.
|
||||
// If so, the strategy method is called, otherwise we open
|
||||
// an undercut limit order at the best current price.
|
||||
match open_order {
|
||||
Some(open_order) => {
|
||||
info!("There is an open order. Calling strategy.");
|
||||
|
||||
self.tracked_positions = self
|
||||
.strategy
|
||||
.on_position_close(open_order, &self.tracked_positions);
|
||||
}
|
||||
None => {
|
||||
info!("Getting current prices...");
|
||||
let current_prices = self.client.current_prices(&self.pair).await?;
|
||||
info!("Calculating best closing price...");
|
||||
let closing_price = self.best_closing_price(&position, ¤t_prices)?;
|
||||
|
||||
info!("Submitting order...");
|
||||
// submitting order
|
||||
let order_form = OrderForm::new(
|
||||
&self.pair,
|
||||
@ -394,6 +401,7 @@ impl OrderManager {
|
||||
Err(e) => error!("Could not submit order: {}", e),
|
||||
Ok(o) => {
|
||||
self.tracked_positions.insert(position.id(), o);
|
||||
info!("Done!");
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -402,7 +410,7 @@ impl OrderManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update(&self) -> Option<Vec<Event>> {
|
||||
pub fn update(&self) -> Result<OptionUpdate, BoxError> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
@ -464,17 +472,16 @@ impl ExchangeManager {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn update_managers(&mut self, tick: u64) -> Result<(), BoxError> {
|
||||
self.update_price_managers(tick).await?;
|
||||
self.update_position_managers(tick).await?;
|
||||
pub async fn update_managers(&mut self, tick: u64) -> Result<OptionUpdate, BoxError> {
|
||||
let (price_opt_events, price_opt_signals) = self.update_price_managers(tick).await?;
|
||||
let (pos_opt_events, pos_opt_signals) = self.update_position_managers(tick).await?;
|
||||
|
||||
Ok(())
|
||||
debug!("{:?}", pos_opt_signals);
|
||||
|
||||
Ok((pos_opt_events, price_opt_signals))
|
||||
}
|
||||
|
||||
async fn update_position_managers(
|
||||
&mut self,
|
||||
tick: u64,
|
||||
) -> Result<Option<Vec<Event>>, BoxError> {
|
||||
async fn update_position_managers(&mut self, tick: u64) -> Result<OptionUpdate, BoxError> {
|
||||
let mut futures: FuturesUnordered<_> = self
|
||||
.position_managers
|
||||
.iter_mut()
|
||||
@ -483,10 +490,10 @@ impl ExchangeManager {
|
||||
|
||||
while let Some(x) = futures.next().await {}
|
||||
|
||||
Ok(None)
|
||||
Ok((None, None))
|
||||
}
|
||||
|
||||
async fn update_price_managers(&mut self, tick: u64) -> Result<Option<Vec<Event>>, BoxError> {
|
||||
async fn update_price_managers(&mut self, tick: u64) -> Result<OptionUpdate, BoxError> {
|
||||
let mut futures: FuturesUnordered<_> = self
|
||||
.price_managers
|
||||
.iter_mut()
|
||||
@ -495,6 +502,6 @@ impl ExchangeManager {
|
||||
|
||||
while let Some(x) = futures.next().await {}
|
||||
|
||||
Ok(None)
|
||||
Ok((None, None))
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ pub trait PositionStrategy: DynClone + Send {
|
||||
&self,
|
||||
position: Position,
|
||||
manager: &PositionManager,
|
||||
) -> (Position, Vec<Event>, Option<OrderForm>);
|
||||
) -> (Position, Option<Vec<Event>>, Option<Vec<SignalKind>>);
|
||||
}
|
||||
|
||||
impl Debug for dyn PositionStrategy {
|
||||
@ -60,7 +60,7 @@ impl TrailingStop {
|
||||
const BREAK_EVEN_PERC: f64 = 0.2;
|
||||
const MIN_PROFIT_PERC: f64 = TrailingStop::BREAK_EVEN_PERC + 0.3;
|
||||
const GOOD_PROFIT_PERC: f64 = TrailingStop::MIN_PROFIT_PERC * 2.5;
|
||||
const MAX_LOSS_PERC: f64 = -1.7;
|
||||
const MAX_LOSS_PERC: f64 = -0.01;
|
||||
|
||||
const TAKER_FEE: f64 = 0.2;
|
||||
|
||||
@ -84,11 +84,11 @@ impl PositionStrategy for TrailingStop {
|
||||
&self,
|
||||
position: Position,
|
||||
manager: &PositionManager,
|
||||
) -> (Position, Vec<Event>, Option<OrderForm>) {
|
||||
) -> (Position, Option<Vec<Event>>, Option<Vec<SignalKind>>) {
|
||||
let mut signals = vec![];
|
||||
let pl_perc = TrailingStop::net_pl_percentage(position.pl_perc(), TrailingStop::TAKER_FEE);
|
||||
let events = vec![];
|
||||
let mut order = None;
|
||||
|
||||
let pl_perc = TrailingStop::net_pl_percentage(position.pl_perc(), TrailingStop::TAKER_FEE);
|
||||
|
||||
let state = {
|
||||
if pl_perc > TrailingStop::GOOD_PROFIT_PERC {
|
||||
@ -114,10 +114,20 @@ impl PositionStrategy for TrailingStop {
|
||||
match opt_pre_pw {
|
||||
Some(prev) => {
|
||||
if prev.profit_state() == Some(state) {
|
||||
return (new_position, events, order);
|
||||
return (
|
||||
new_position,
|
||||
(!events.is_empty()).then_some(events),
|
||||
(!signals.is_empty()).then_some(signals),
|
||||
);
|
||||
}
|
||||
}
|
||||
None => return (new_position, events, order),
|
||||
None => {
|
||||
return (
|
||||
new_position,
|
||||
(!events.is_empty()).then_some(events),
|
||||
(!signals.is_empty()).then_some(signals),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let events = {
|
||||
@ -158,7 +168,11 @@ impl PositionStrategy for TrailingStop {
|
||||
events
|
||||
};
|
||||
|
||||
return (new_position, events, order);
|
||||
return (
|
||||
new_position,
|
||||
(!events.is_empty()).then_some(events),
|
||||
(!signals.is_empty()).then_some(signals),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user