positions with strategy working
This commit is contained in:
parent
ae648b70a4
commit
0e2673837c
7
rustybot/Cargo.lock
generated
7
rustybot/Cargo.lock
generated
@ -223,6 +223,12 @@ dependencies = [
|
|||||||
"generic-array 0.14.4",
|
"generic-array 0.14.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dyn-clone"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
version = "0.8.26"
|
version = "0.8.26"
|
||||||
@ -1056,6 +1062,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"bitfinex",
|
"bitfinex",
|
||||||
|
"dyn-clone",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"regex",
|
"regex",
|
||||||
"tokio 0.2.24",
|
"tokio 0.2.24",
|
||||||
|
@ -13,3 +13,4 @@ tokio-tungstenite = "*"
|
|||||||
futures-util = { version = "0.3", default-features = false, features = ["async-await", "sink", "std"] }
|
futures-util = { version = "0.3", default-features = false, features = ["async-await", "sink", "std"] }
|
||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
regex = "1"
|
regex = "1"
|
||||||
|
dyn-clone = "1"
|
@ -9,17 +9,16 @@ use tokio::time::delay_for;
|
|||||||
use crate::connectors::Connector;
|
use crate::connectors::Connector;
|
||||||
use crate::currency::{Symbol, SymbolPair};
|
use crate::currency::{Symbol, SymbolPair};
|
||||||
use crate::pairs::PairStatus;
|
use crate::pairs::PairStatus;
|
||||||
|
use crate::strategy::Strategy;
|
||||||
use crate::ticker::Ticker;
|
use crate::ticker::Ticker;
|
||||||
use crate::BoxError;
|
use crate::BoxError;
|
||||||
|
|
||||||
pub struct BfxBot<'a> {
|
pub struct BfxBot<'a> {
|
||||||
connector: Box<dyn Connector + 'a>,
|
connector: Box<dyn Connector + 'a>,
|
||||||
ticker: Ticker,
|
ticker: Ticker,
|
||||||
pair_status: Vec<PairStatus>,
|
pair_statuses: Vec<PairStatus<'a>>,
|
||||||
quote: Symbol,
|
quote: Symbol,
|
||||||
trading_symbols: Vec<Symbol>,
|
trading_symbols: Vec<Symbol>,
|
||||||
// account_info: String,
|
|
||||||
// ledger: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> BfxBot<'a> {
|
impl<'a> BfxBot<'a> {
|
||||||
@ -32,18 +31,24 @@ impl<'a> BfxBot<'a> {
|
|||||||
BfxBot {
|
BfxBot {
|
||||||
connector: Box::new(connector),
|
connector: Box::new(connector),
|
||||||
ticker: Ticker::new(tick_duration),
|
ticker: Ticker::new(tick_duration),
|
||||||
pair_status: trading_symbols
|
pair_statuses: trading_symbols
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| SymbolPair::new(quote.clone(), x.clone()))
|
.map(|x| SymbolPair::new(quote.clone(), x.clone()))
|
||||||
.map(|x| PairStatus::new(x, 1, None))
|
.map(|x| PairStatus::new(x, 1, None))
|
||||||
.collect(),
|
.collect(),
|
||||||
quote,
|
quote,
|
||||||
// account_info: String::new(),
|
|
||||||
// ledger: String::new(),
|
|
||||||
trading_symbols,
|
trading_symbols,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_strategy(mut self, strategy: Box<dyn Strategy>) -> Self {
|
||||||
|
self.pair_statuses
|
||||||
|
.iter_mut()
|
||||||
|
.for_each(|x| x.set_strategy(dyn_clone::clone_box(&*strategy)));
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn current_prices(&self, symbol: Symbol) -> Result<TradingPairTicker, BoxError> {
|
pub async fn current_prices(&self, symbol: Symbol) -> Result<TradingPairTicker, BoxError> {
|
||||||
let trading_pair = SymbolPair::new(self.quote.clone(), symbol.clone());
|
let trading_pair = SymbolPair::new(self.quote.clone(), symbol.clone());
|
||||||
|
|
||||||
@ -54,17 +59,35 @@ impl<'a> BfxBot<'a> {
|
|||||||
self.connector.current_prices(&trading_pair).await
|
self.connector.current_prices(&trading_pair).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update(&mut self) {
|
pub async fn start_loop(&mut self) -> Result<(), BoxError> {
|
||||||
println!("Updating...");
|
if let Err(e) = self.update_pair_statuses().await {
|
||||||
delay_for(self.ticker.duration()).await;
|
println!("Error while updating pairs at first start: {}", e);
|
||||||
self.ticker.inc();
|
|
||||||
// self.update_pairs().await;
|
|
||||||
println!("Done!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// async fn update_pairs(&mut self) {
|
loop {
|
||||||
// let active_positions = self.bfx.positions.active_positions().await?;
|
self.update().await;
|
||||||
//
|
}
|
||||||
// for p in active_positions {}
|
}
|
||||||
// }
|
|
||||||
|
async fn update(&mut self) {
|
||||||
|
delay_for(self.ticker.duration()).await;
|
||||||
|
self.ticker.inc();
|
||||||
|
|
||||||
|
if let Err(e) = self.update_pair_statuses().await {
|
||||||
|
println!("Error while updating pairs: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn update_pair_statuses(&mut self) -> Result<(), BoxError> {
|
||||||
|
for status in &mut self.pair_statuses {
|
||||||
|
// add positions for each pair
|
||||||
|
self.connector
|
||||||
|
.active_positions(status.pair())
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.for_each(|x| status.add_position(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ use regex::Regex;
|
|||||||
|
|
||||||
use crate::BoxError;
|
use crate::BoxError;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Hash)]
|
#[derive(Clone, PartialEq, Hash, Debug, Eq)]
|
||||||
pub struct Symbol {
|
pub struct Symbol {
|
||||||
name: Cow<'static, str>,
|
name: Cow<'static, str>,
|
||||||
}
|
}
|
||||||
@ -26,6 +26,8 @@ impl Symbol {
|
|||||||
pub const BTC: Symbol = Symbol::new_static("BTC");
|
pub const BTC: Symbol = Symbol::new_static("BTC");
|
||||||
pub const ETH: Symbol = Symbol::new_static("ETH");
|
pub const ETH: Symbol = Symbol::new_static("ETH");
|
||||||
pub const LTC: Symbol = Symbol::new_static("LTC");
|
pub const LTC: Symbol = Symbol::new_static("LTC");
|
||||||
|
pub const TESTBTC: Symbol = Symbol::new_static("TESTBTC");
|
||||||
|
pub const TESTUSD: Symbol = Symbol::new_static("TESTUSD");
|
||||||
pub const USD: Symbol = Symbol::new_static("USD");
|
pub const USD: Symbol = Symbol::new_static("USD");
|
||||||
pub const GBP: Symbol = Symbol::new_static("GBP");
|
pub const GBP: Symbol = Symbol::new_static("GBP");
|
||||||
pub const EUR: Symbol = Symbol::new_static("EUR");
|
pub const EUR: Symbol = Symbol::new_static("EUR");
|
||||||
@ -53,7 +55,7 @@ impl Display for Symbol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct SymbolPair {
|
pub struct SymbolPair {
|
||||||
quote: Symbol,
|
quote: Symbol,
|
||||||
base: Symbol,
|
base: Symbol,
|
||||||
@ -79,7 +81,7 @@ impl SymbolPair {
|
|||||||
|
|
||||||
impl Into<String> for SymbolPair {
|
impl Into<String> for SymbolPair {
|
||||||
fn into(self) -> String {
|
fn into(self) -> String {
|
||||||
format!("{}{}", self.base, self.quote)
|
format!("{}/{}", self.base, self.quote)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +89,7 @@ impl TryFrom<&str> for SymbolPair {
|
|||||||
type Error = BoxError;
|
type Error = BoxError;
|
||||||
|
|
||||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||||
const REGEX: &str = r"^[t|f](?P<base>\w{3,4}):?(?P<quote>\w{3,4})";
|
const REGEX: &str = r"^[t|f](?P<base>\w{3,7}):?(?P<quote>\w{3,7})";
|
||||||
|
|
||||||
let captures = Regex::new(REGEX)?.captures(&value).ok_or("Invalid input")?;
|
let captures = Regex::new(REGEX)?.captures(&value).ok_or("Invalid input")?;
|
||||||
let quote = captures.name("quote").ok_or("Quote not found")?.as_str();
|
let quote = captures.name("quote").ok_or("Quote not found")?.as_str();
|
||||||
@ -102,7 +104,7 @@ impl TryFrom<&str> for SymbolPair {
|
|||||||
|
|
||||||
impl Display for SymbolPair {
|
impl Display for SymbolPair {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{}{}", self.base, self.quote)
|
write!(f, "{}/{}", self.base, self.quote)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,13 +8,13 @@ use crate::pairs::PairStatus;
|
|||||||
use crate::positions::{Position, PositionProfitState, PositionState};
|
use crate::positions::{Position, PositionProfitState, PositionState};
|
||||||
use crate::BoxError;
|
use crate::BoxError;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub enum SignalKind {
|
pub enum SignalKind {
|
||||||
ClosePosition,
|
ClosePosition,
|
||||||
OpenPosition,
|
OpenPosition,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct EventMetadata {
|
pub struct EventMetadata {
|
||||||
position_id: Option<u64>,
|
position_id: Option<u64>,
|
||||||
order_id: Option<u64>,
|
order_id: Option<u64>,
|
||||||
@ -29,7 +29,7 @@ impl EventMetadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
pub enum EventKind {
|
pub enum EventKind {
|
||||||
NewMinimum,
|
NewMinimum,
|
||||||
NewMaximum,
|
NewMaximum,
|
||||||
@ -45,7 +45,7 @@ pub enum EventKind {
|
|||||||
Any,
|
Any,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct Event {
|
pub struct Event {
|
||||||
kind: EventKind,
|
kind: EventKind,
|
||||||
tick: u64,
|
tick: u64,
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use tokio::time::{delay_for, Duration};
|
use tokio::time::{delay_for, Duration};
|
||||||
|
|
||||||
use crate::bot::BfxBot;
|
use crate::bot::BfxBot;
|
||||||
|
use crate::connectors::BfxWrapper;
|
||||||
use crate::currency::{Symbol, SymbolPair};
|
use crate::currency::{Symbol, SymbolPair};
|
||||||
|
use crate::strategy::TrailingStop;
|
||||||
|
|
||||||
mod bot;
|
mod bot;
|
||||||
mod connectors;
|
mod connectors;
|
||||||
@ -17,24 +19,17 @@ pub type BoxError = Box<dyn std::error::Error + Send + Sync>;
|
|||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), BoxError> {
|
async fn main() -> Result<(), BoxError> {
|
||||||
// let test_api_key = "P1EVE68DJByDAkGQvpIkTwfrbYXd2Vo2ZaIhTYb9vx2";
|
let test_api_key = "P1EVE68DJByDAkGQvpIkTwfrbYXd2Vo2ZaIhTYb9vx2";
|
||||||
// let test_api_secret = "1nicg8z0zKVEt5Rb7ZDpIYjVYVTgvCaCPMZqB0niFli";
|
let test_api_secret = "1nicg8z0zKVEt5Rb7ZDpIYjVYVTgvCaCPMZqB0niFli";
|
||||||
//
|
//
|
||||||
// let mut bot = BfxBot::new(
|
let bfx = BfxWrapper::new(test_api_key, test_api_secret);
|
||||||
// test_api_key,
|
let mut bot = BfxBot::new(
|
||||||
// test_api_secret,
|
bfx,
|
||||||
// vec![Symbol::BTC, Symbol::ETH, Symbol::XMR],
|
vec![Symbol::TESTBTC],
|
||||||
// Symbol::USD,
|
Symbol::TESTUSD,
|
||||||
// Duration::new(20, 0),
|
Duration::new(20, 0),
|
||||||
// );
|
)
|
||||||
//
|
.with_strategy(Box::new(TrailingStop::new()));
|
||||||
// loop {
|
|
||||||
// let ticker = bot.current_prices("ETH".into()).await?;
|
|
||||||
// bot.update().await;
|
|
||||||
//
|
|
||||||
// // let ticker = bot.current_prices("ETH".into()).await?;
|
|
||||||
// println!("{:?}", ticker);
|
|
||||||
// }
|
|
||||||
|
|
||||||
Ok(())
|
Ok(bot.start_loop().await?)
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::currency::SymbolPair;
|
use crate::currency::SymbolPair;
|
||||||
use crate::events::{Event, EventDispatcher};
|
use crate::events::{Event, EventDispatcher, SignalKind};
|
||||||
use crate::orders::Order;
|
use crate::orders::Order;
|
||||||
use crate::positions::Position;
|
use crate::positions::Position;
|
||||||
use crate::strategy::Strategy;
|
use crate::strategy::Strategy;
|
||||||
|
|
||||||
pub struct PairStatus {
|
pub struct PairStatus<'a> {
|
||||||
pair: SymbolPair,
|
pair: SymbolPair,
|
||||||
dispatcher: EventDispatcher,
|
dispatcher: EventDispatcher,
|
||||||
prices: HashMap<u64, f64>,
|
prices: HashMap<u64, f64>,
|
||||||
@ -14,10 +14,11 @@ pub struct PairStatus {
|
|||||||
orders: HashMap<u64, Vec<Order>>,
|
orders: HashMap<u64, Vec<Order>>,
|
||||||
positions: HashMap<u64, Vec<Position>>,
|
positions: HashMap<u64, Vec<Position>>,
|
||||||
current_tick: u64,
|
current_tick: u64,
|
||||||
strategy: Option<Box<dyn Strategy>>,
|
strategy: Option<Box<dyn Strategy + 'a>>,
|
||||||
|
signals: HashMap<u64, SignalKind>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PairStatus {
|
impl<'a> PairStatus<'a> {
|
||||||
pub fn new(pair: SymbolPair, current_tick: u64, strategy: Option<Box<dyn Strategy>>) -> Self {
|
pub fn new(pair: SymbolPair, current_tick: u64, strategy: Option<Box<dyn Strategy>>) -> Self {
|
||||||
PairStatus {
|
PairStatus {
|
||||||
pair,
|
pair,
|
||||||
@ -25,52 +26,82 @@ impl PairStatus {
|
|||||||
prices: HashMap::new(),
|
prices: HashMap::new(),
|
||||||
events: Vec::new(),
|
events: Vec::new(),
|
||||||
positions: HashMap::new(),
|
positions: HashMap::new(),
|
||||||
|
orders: HashMap::new(),
|
||||||
|
signals: HashMap::new(),
|
||||||
current_tick,
|
current_tick,
|
||||||
strategy,
|
strategy,
|
||||||
orders: HashMap::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_position(&mut self, position: Position) {
|
pub fn add_position(&mut self, position: Position) {
|
||||||
let (pw, events, signals) = {
|
let (new_position, events, signals) = {
|
||||||
match &self.strategy {
|
match &self.strategy {
|
||||||
Some(strategy) => strategy.position_on_new_tick(&position, &self),
|
Some(strategy) => strategy.position_on_new_tick(&position, &self),
|
||||||
None => (
|
None => (position, vec![], vec![]),
|
||||||
position,
|
|
||||||
// PositionWrapper::new(position.clone(), position.pl(), position.pl_perc(), None),
|
|
||||||
vec![],
|
|
||||||
vec![],
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.positions
|
self.positions
|
||||||
.entry(self.current_tick)
|
.entry(self.current_tick)
|
||||||
.or_default()
|
.or_default()
|
||||||
.push(pw.clone());
|
.push(new_position.clone());
|
||||||
|
|
||||||
// calling position state callbacks
|
// calling position state callbacks
|
||||||
self.dispatcher.call_position_state_handlers(&pw, &self);
|
self.dispatcher
|
||||||
|
.call_position_state_handlers(&new_position, &self);
|
||||||
|
|
||||||
// adding events and calling callbacks
|
// adding events and calling callbacks
|
||||||
for e in events {
|
for e in events {
|
||||||
self.add_event(e);
|
self.add_event(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// adding signals to current tick vector
|
||||||
|
for s in signals {
|
||||||
|
self.add_signal(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_event(&mut self, event: Event) {
|
println!(
|
||||||
|
"EVENTS: {:?} | SIGNALS: {:?} | POSITION: {:?}",
|
||||||
|
self.events, self.signals, new_position
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_event(&mut self, event: Event) {
|
||||||
self.events.push(event);
|
self.events.push(event);
|
||||||
|
|
||||||
self.dispatcher.call_event_handlers(&event, &self);
|
self.dispatcher.call_event_handlers(&event, &self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_signal(&mut self, signal: SignalKind) {
|
||||||
|
self.signals.insert(self.current_tick(), signal);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn current_tick(&self) -> u64 {
|
pub fn current_tick(&self) -> u64 {
|
||||||
self.current_tick
|
self.current_tick
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn previous_pw(&self, id: u64) -> Option<&Position> {
|
pub fn set_strategy(&mut self, strategy: Box<dyn Strategy + 'a>) {
|
||||||
|
self.strategy = Some(strategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pair(&self) -> &SymbolPair {
|
||||||
|
&self.pair
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn position_previous_tick(&self, id: u64, tick: Option<u64>) -> Option<&Position> {
|
||||||
|
let tick = match tick {
|
||||||
|
Some(tick) => {
|
||||||
|
if tick < 1 {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
tick
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => self.current_tick() - 1,
|
||||||
|
};
|
||||||
|
|
||||||
self.positions
|
self.positions
|
||||||
.get(&(self.current_tick - 1))
|
.get(&tick)
|
||||||
.and_then(|x| x.iter().find(|x| x.position_id() == id))
|
.and_then(|x| x.iter().find(|x| x.position_id() == id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::currency::{Symbol, SymbolPair};
|
use crate::currency::{Symbol, SymbolPair};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Position {
|
pub struct Position {
|
||||||
pair: SymbolPair,
|
pair: SymbolPair,
|
||||||
state: PositionState,
|
state: PositionState,
|
||||||
@ -91,7 +91,7 @@ impl Position {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||||
pub enum PositionProfitState {
|
pub enum PositionProfitState {
|
||||||
Critical,
|
Critical,
|
||||||
Loss,
|
Loss,
|
||||||
@ -111,7 +111,7 @@ impl PositionProfitState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||||
pub enum PositionState {
|
pub enum PositionState {
|
||||||
Closed,
|
Closed,
|
||||||
Open,
|
Open,
|
||||||
|
@ -3,8 +3,9 @@ use std::collections::HashMap;
|
|||||||
use crate::events::{Event, EventKind, EventMetadata, SignalKind};
|
use crate::events::{Event, EventKind, EventMetadata, SignalKind};
|
||||||
use crate::pairs::PairStatus;
|
use crate::pairs::PairStatus;
|
||||||
use crate::positions::{Position, PositionProfitState, PositionState};
|
use crate::positions::{Position, PositionProfitState, PositionState};
|
||||||
|
use dyn_clone::DynClone;
|
||||||
|
|
||||||
pub trait Strategy {
|
pub trait Strategy: DynClone {
|
||||||
fn position_on_new_tick(
|
fn position_on_new_tick(
|
||||||
&self,
|
&self,
|
||||||
position: &Position,
|
position: &Position,
|
||||||
@ -12,7 +13,8 @@ pub trait Strategy {
|
|||||||
) -> (Position, Vec<Event>, Vec<SignalKind>);
|
) -> (Position, Vec<Event>, Vec<SignalKind>);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TrailingStop {
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct TrailingStop {
|
||||||
stop_percentages: HashMap<u64, f64>,
|
stop_percentages: HashMap<u64, f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,18 +64,17 @@ impl Strategy for TrailingStop {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let opt_pre_pw = status.previous_pw(position.position_id());
|
let opt_pre_pw = status.position_previous_tick(position.position_id(), None);
|
||||||
let event_metadata = EventMetadata::new(Some(position.position_id()), None);
|
let event_metadata = EventMetadata::new(Some(position.position_id()), None);
|
||||||
// let pw = PositionWrapper::new(position.clone(), position.pl(), pl_perc, Some(state));
|
let new_position = position.clone().with_profit_state(Some(state));
|
||||||
let pw = position.clone();
|
|
||||||
|
|
||||||
match opt_pre_pw {
|
match opt_pre_pw {
|
||||||
Some(prev) => {
|
Some(prev) => {
|
||||||
if prev.profit_state() == Some(state) {
|
if prev.profit_state() == Some(state) {
|
||||||
return (pw, events, signals);
|
return (new_position, events, signals);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => return (pw, events, signals),
|
None => return (new_position, events, signals),
|
||||||
};
|
};
|
||||||
|
|
||||||
let events = {
|
let events = {
|
||||||
@ -114,6 +115,6 @@ impl Strategy for TrailingStop {
|
|||||||
events
|
events
|
||||||
};
|
};
|
||||||
|
|
||||||
return (pw, events, signals);
|
return (new_position, events, signals);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user