renamed strategies
This commit is contained in:
parent
6e848c35e3
commit
7f848223b9
@ -16,7 +16,7 @@ use crate::events::{ActorMessage, Event, Message};
|
|||||||
use crate::models::{
|
use crate::models::{
|
||||||
ActiveOrder, OrderBook, OrderForm, OrderKind, Position, PriceTicker, TradingPlatform,
|
ActiveOrder, OrderBook, OrderForm, OrderKind, Position, PriceTicker, TradingPlatform,
|
||||||
};
|
};
|
||||||
use crate::strategy::{FastOrderStrategy, OrderStrategy, PositionStrategy, TrailingStop};
|
use crate::strategy::{HiddenTrailingStop, MarketEnforce, OrderStrategy, PositionStrategy};
|
||||||
use crate::BoxError;
|
use crate::BoxError;
|
||||||
|
|
||||||
pub type OptionUpdate = (Option<Vec<Event>>, Option<Vec<Message>>);
|
pub type OptionUpdate = (Option<Vec<Event>>, Option<Vec<Message>>);
|
||||||
@ -534,12 +534,12 @@ impl PairManager {
|
|||||||
order_manager: OrderManagerHandle::new(
|
order_manager: OrderManagerHandle::new(
|
||||||
pair.clone(),
|
pair.clone(),
|
||||||
client.clone(),
|
client.clone(),
|
||||||
Box::new(FastOrderStrategy::default()),
|
Box::new(MarketEnforce::default()),
|
||||||
),
|
),
|
||||||
position_manager: PositionManagerHandle::new(
|
position_manager: PositionManagerHandle::new(
|
||||||
pair,
|
pair,
|
||||||
client,
|
client,
|
||||||
Box::new(TrailingStop::new()),
|
Box::new(HiddenTrailingStop::new()),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,15 +67,15 @@ impl Debug for dyn OrderStrategy {
|
|||||||
***************/
|
***************/
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct TrailingStop {
|
pub struct HiddenTrailingStop {
|
||||||
stop_percentages: HashMap<u64, f64>,
|
stop_percentages: HashMap<u64, f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TrailingStop {
|
impl HiddenTrailingStop {
|
||||||
// in percentage
|
// in percentage
|
||||||
const CAPITAL_MAX_LOSS: f64 = 17.5;
|
const CAPITAL_MAX_LOSS: f64 = 15.0;
|
||||||
const CAPITAL_MIN_PROFIT: f64 = 10.0;
|
const CAPITAL_MIN_PROFIT: f64 = 9.0;
|
||||||
const CAPITAL_GOOD_PROFIT: f64 = 20.0;
|
const CAPITAL_GOOD_PROFIT: f64 = HiddenTrailingStop::CAPITAL_MIN_PROFIT * 2.0;
|
||||||
|
|
||||||
// in percentage
|
// in percentage
|
||||||
const MIN_PROFIT_TRAILING_DELTA: f64 = 0.2;
|
const MIN_PROFIT_TRAILING_DELTA: f64 = 0.2;
|
||||||
@ -83,14 +83,17 @@ impl TrailingStop {
|
|||||||
|
|
||||||
const LEVERAGE: f64 = 15.0;
|
const LEVERAGE: f64 = 15.0;
|
||||||
|
|
||||||
const MIN_PROFIT_PERC: f64 = (TrailingStop::CAPITAL_MIN_PROFIT / TrailingStop::LEVERAGE)
|
const MIN_PROFIT_PERC: f64 = (HiddenTrailingStop::CAPITAL_MIN_PROFIT
|
||||||
+ TrailingStop::MIN_PROFIT_TRAILING_DELTA;
|
/ HiddenTrailingStop::LEVERAGE)
|
||||||
const GOOD_PROFIT_PERC: f64 = (TrailingStop::CAPITAL_GOOD_PROFIT / TrailingStop::LEVERAGE)
|
+ HiddenTrailingStop::MIN_PROFIT_TRAILING_DELTA;
|
||||||
+ TrailingStop::GOOD_PROFIT_TRAILING_DELTA;
|
const GOOD_PROFIT_PERC: f64 = (HiddenTrailingStop::CAPITAL_GOOD_PROFIT
|
||||||
const MAX_LOSS_PERC: f64 = -(TrailingStop::CAPITAL_MAX_LOSS / TrailingStop::LEVERAGE);
|
/ HiddenTrailingStop::LEVERAGE)
|
||||||
|
+ HiddenTrailingStop::GOOD_PROFIT_TRAILING_DELTA;
|
||||||
|
const MAX_LOSS_PERC: f64 =
|
||||||
|
-(HiddenTrailingStop::CAPITAL_MAX_LOSS / HiddenTrailingStop::LEVERAGE);
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
TrailingStop {
|
HiddenTrailingStop {
|
||||||
stop_percentages: HashMap::new(),
|
stop_percentages: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,8 +101,10 @@ impl TrailingStop {
|
|||||||
fn update_stop_percentage(&mut self, position: &Position) {
|
fn update_stop_percentage(&mut self, position: &Position) {
|
||||||
if let Some(profit_state) = position.profit_state() {
|
if let Some(profit_state) = position.profit_state() {
|
||||||
let profit_state_delta = match profit_state {
|
let profit_state_delta = match profit_state {
|
||||||
PositionProfitState::MinimumProfit => Some(TrailingStop::MIN_PROFIT_TRAILING_DELTA),
|
PositionProfitState::MinimumProfit => {
|
||||||
PositionProfitState::Profit => Some(TrailingStop::GOOD_PROFIT_TRAILING_DELTA),
|
Some(HiddenTrailingStop::MIN_PROFIT_TRAILING_DELTA)
|
||||||
|
}
|
||||||
|
PositionProfitState::Profit => Some(HiddenTrailingStop::GOOD_PROFIT_TRAILING_DELTA),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -125,8 +130,10 @@ impl TrailingStop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
info!(
|
info!(
|
||||||
"\tState: {:?} | PL%: {:0.2} | Stop: {:0.2}",
|
"\tState: {:?} | PL: {:0.2}{} ({:0.2}%) | Stop: {:0.2}",
|
||||||
position.profit_state().unwrap(),
|
position.profit_state().unwrap(),
|
||||||
|
position.pl(),
|
||||||
|
position.pair().quote(),
|
||||||
position.pl_perc(),
|
position.pl_perc(),
|
||||||
self.stop_percentages.get(&position.id()).unwrap_or(&0.0)
|
self.stop_percentages.get(&position.id()).unwrap_or(&0.0)
|
||||||
);
|
);
|
||||||
@ -134,9 +141,9 @@ impl TrailingStop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PositionStrategy for TrailingStop {
|
impl PositionStrategy for HiddenTrailingStop {
|
||||||
fn name(&self) -> String {
|
fn name(&self) -> String {
|
||||||
"Trailing stop".into()
|
"Hidden Trailing Stop".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the profit state of an open position
|
/// Sets the profit state of an open position
|
||||||
@ -149,15 +156,15 @@ impl PositionStrategy for TrailingStop {
|
|||||||
let pl_perc = position.pl_perc();
|
let pl_perc = position.pl_perc();
|
||||||
|
|
||||||
let state = {
|
let state = {
|
||||||
if pl_perc > TrailingStop::GOOD_PROFIT_PERC {
|
if pl_perc > HiddenTrailingStop::GOOD_PROFIT_PERC {
|
||||||
PositionProfitState::Profit
|
PositionProfitState::Profit
|
||||||
} else if TrailingStop::MIN_PROFIT_PERC <= pl_perc
|
} else if HiddenTrailingStop::MIN_PROFIT_PERC <= pl_perc
|
||||||
&& pl_perc < TrailingStop::GOOD_PROFIT_PERC
|
&& pl_perc < HiddenTrailingStop::GOOD_PROFIT_PERC
|
||||||
{
|
{
|
||||||
PositionProfitState::MinimumProfit
|
PositionProfitState::MinimumProfit
|
||||||
} else if (0.0..TrailingStop::MIN_PROFIT_PERC).contains(&pl_perc) {
|
} else if (0.0..HiddenTrailingStop::MIN_PROFIT_PERC).contains(&pl_perc) {
|
||||||
PositionProfitState::BreakEven
|
PositionProfitState::BreakEven
|
||||||
} else if (TrailingStop::MAX_LOSS_PERC..0.0).contains(&pl_perc) {
|
} else if (HiddenTrailingStop::MAX_LOSS_PERC..0.0).contains(&pl_perc) {
|
||||||
PositionProfitState::Loss
|
PositionProfitState::Loss
|
||||||
} else {
|
} else {
|
||||||
PositionProfitState::Critical
|
PositionProfitState::Critical
|
||||||
@ -249,21 +256,21 @@ impl PositionStrategy for TrailingStop {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct FastOrderStrategy {
|
pub struct MarketEnforce {
|
||||||
// threshold (%) for which we trigger a market order
|
// threshold (%) for which we trigger a market order
|
||||||
// to close an open position
|
// to close an open position
|
||||||
threshold: f64,
|
threshold: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FastOrderStrategy {
|
impl Default for MarketEnforce {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self { threshold: 0.15 }
|
Self { threshold: 0.15 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OrderStrategy for FastOrderStrategy {
|
impl OrderStrategy for MarketEnforce {
|
||||||
fn name(&self) -> String {
|
fn name(&self) -> String {
|
||||||
"Fast order strategy".into()
|
"Market Enforce".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_open_order(
|
fn on_open_order(
|
||||||
@ -294,7 +301,7 @@ impl OrderStrategy for FastOrderStrategy {
|
|||||||
messages.push(Message::SubmitOrder {
|
messages.push(Message::SubmitOrder {
|
||||||
order: OrderForm::new(
|
order: OrderForm::new(
|
||||||
order.symbol.clone(),
|
order.symbol.clone(),
|
||||||
OrderKind::Market {},
|
OrderKind::Market,
|
||||||
*order.details.platform(),
|
*order.details.platform(),
|
||||||
order.details.amount(),
|
order.details.amount(),
|
||||||
),
|
),
|
||||||
@ -303,44 +310,4 @@ impl OrderStrategy for FastOrderStrategy {
|
|||||||
|
|
||||||
Ok((None, (!messages.is_empty()).then_some(messages)))
|
Ok((None, (!messages.is_empty()).then_some(messages)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn on_position_order(
|
|
||||||
// &self,
|
|
||||||
// order: &ActiveOrder,
|
|
||||||
// _: &Position,
|
|
||||||
// order_book: &OrderBook,
|
|
||||||
// ) -> Result<OptionUpdate, BoxError> {
|
|
||||||
// let mut messages = vec![];
|
|
||||||
//
|
|
||||||
// // long
|
|
||||||
// let offer_comparison = {
|
|
||||||
// if order.current_form.amount() > 0.0 {
|
|
||||||
// order_book.highest_bid()
|
|
||||||
// } else {
|
|
||||||
// order_book.lowest_ask()
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// // if the best offer is higher than our threshold,
|
|
||||||
// // ask the manager to close the position with a market order
|
|
||||||
// let order_price = order
|
|
||||||
// .current_form
|
|
||||||
// .price()
|
|
||||||
// .ok_or("The active order does not have a price!")?;
|
|
||||||
// let delta = (1.0 - (offer_comparison / order_price)).abs() * 100.0;
|
|
||||||
//
|
|
||||||
// if delta > self.threshold {
|
|
||||||
// messages.push(Message::SubmitOrder {
|
|
||||||
// order: OrderForm::new(
|
|
||||||
// order.symbol.clone(),
|
|
||||||
// OrderKind::Market {
|
|
||||||
// amount: order.current_form.amount(),
|
|
||||||
// },
|
|
||||||
// order.current_form.platform().clone(),
|
|
||||||
// ),
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Ok((None, (!messages.is_empty()).then_some(messages)))
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user