From cb7f53b255894400cef8f18232725063f7683fa1 Mon Sep 17 00:00:00 2001 From: eric Date: Tue, 4 Dec 2018 09:58:43 +0800 Subject: [PATCH 1/9] 1. adjust log format in LogTradesAnalysis Analyze 2. adjust profit calculation in LogTradesAnalysis Analyze --- analysis.go | 14 ++++++++++---- order.go | 11 +++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/analysis.go b/analysis.go index c45c633..5ab27fd 100644 --- a/analysis.go +++ b/analysis.go @@ -60,10 +60,16 @@ type LogTradesAnalysis struct { // Analyze logs trades to provided io.Writer func (lta LogTradesAnalysis) Analyze(record *TradingRecord) float64 { logOrder := func(trade *Position) { - fmt.Fprintln(lta.Writer, fmt.Sprintf("%s - enter with buy %s (%s @ $%s)", trade.EntranceOrder().ExecutionTime.UTC().Format(time.RFC822), trade.EntranceOrder().Security, trade.EntranceOrder().Amount, trade.EntranceOrder().Price)) - fmt.Fprintln(lta.Writer, fmt.Sprintf("%s - exit with sell %s (%s @ $%s)", trade.ExitOrder().ExecutionTime.UTC().Format(time.RFC822), trade.ExitOrder().Security, trade.ExitOrder().Amount, trade.ExitOrder().Price)) - - profit := trade.ExitValue().Sub(trade.CostBasis()) + fmt.Fprintln(lta.Writer, fmt.Sprintf("%s - enter with %s %s (%s @ $%s)", + trade.EntranceOrder().ExecutionTime.Format(time.RFC822), trade.EntranceOrder().Side, trade.EntranceOrder().Security, trade.EntranceOrder().Amount, trade.EntranceOrder().Price)) + fmt.Fprintln(lta.Writer, fmt.Sprintf("%s - exit with %s %s (%s @ $%s)", + trade.ExitOrder().ExecutionTime.Format(time.RFC822), trade.EntranceOrder().Side, trade.ExitOrder().Security, trade.ExitOrder().Amount, trade.ExitOrder().Price)) + profit := big.ZERO + if trade.IsLong() { + profit = trade.ExitValue().Sub(trade.CostBasis()) + } else { + profit = trade.CostBasis().Sub(trade.ExitValue()) + } fmt.Fprintln(lta.Writer, fmt.Sprintf("Profit: $%s", profit)) } diff --git a/order.go b/order.go index a8aedec..d824235 100644 --- a/order.go +++ b/order.go @@ -15,6 +15,17 @@ const ( SELL ) +func (os OrderSide) String() string { + switch os { + case BUY: + return "BUY" + case SELL: + return "SELL" + default: + return "UNKNOWN" + } +} + // Order represents a trade execution (buy or sell) with associated metadata. type Order struct { Side OrderSide From abdf03e09f17c4af88fe20a0f63f53bbb44dbe1d Mon Sep 17 00:00:00 2001 From: glacier2002 Date: Tue, 4 Dec 2018 23:50:19 +0800 Subject: [PATCH 2/9] update total profit analysize --- analysis.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/analysis.go b/analysis.go index 5ab27fd..36d0934 100644 --- a/analysis.go +++ b/analysis.go @@ -24,8 +24,11 @@ func (tps TotalProfitAnalysis) Analyze(record *TradingRecord) float64 { if trade.IsClosed() { costBasis := trade.CostBasis() exitValue := trade.ExitValue() - - totalProfit = totalProfit.Add(exitValue.Sub(costBasis)) + if trade.IsLong() { + totalProfit = totalProfit.Add(exitValue.Sub(costBasis)) + } else { + totalProfit = totalProfit.Add(costBasis.Sub(exitValue)) + } } } From 8cdec0558fb713cbf58dfa8b2ab152ee080c2ff9 Mon Sep 17 00:00:00 2001 From: glacier2002 Date: Thu, 13 Dec 2018 23:26:22 +0800 Subject: [PATCH 3/9] 1. fix bug in stop loss and adjust it with long/short order 2. add stop gain rule --- rule_stop.go | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/rule_stop.go b/rule_stop.go index 063840c..33d35fe 100644 --- a/rule_stop.go +++ b/rule_stop.go @@ -1,12 +1,19 @@ package techan -import "github.com/sdcoffey/big" +import ( + "github.com/sdcoffey/big" +) type stopLossRule struct { Indicator tolerance big.Decimal } +type stopGainRule struct { + Indicator + tolerance big.Decimal +} + // NewStopLossRule returns a new rule that is satisfied when the given loss tolerance (a percentage) is met or exceeded. // Loss tolerance should be a value between -1 and 1. func NewStopLossRule(series *TimeSeries, lossTolerance float64) Rule { @@ -20,8 +27,31 @@ func (slr stopLossRule) IsSatisfied(index int, record *TradingRecord) bool { if !record.CurrentPosition().IsOpen() { return false } - - openPrice := record.CurrentPosition().CostBasis() + openPrice := record.CurrentPosition().EntranceOrder().Price loss := slr.Indicator.Calculate(index).Div(openPrice).Sub(big.ONE) + if record.currentPosition.IsShort() { + loss = loss.Neg() + } return loss.LTE(slr.tolerance) } + +// NewStopLossRule returns a new rule that is satisfied when the given loss tolerance (a percentage) is met or exceeded. +// Loss tolerance should be a value between -1 and 1. +func NewStopGainRule(series *TimeSeries, gainTolerance float64) Rule { + return stopGainRule{ + Indicator: NewClosePriceIndicator(series), + tolerance: big.NewDecimal(gainTolerance), + } +} + +func (sgr stopGainRule) IsSatisfied(index int, record *TradingRecord) bool { + if !record.CurrentPosition().IsOpen() { + return false + } + openPrice := record.CurrentPosition().EntranceOrder().Price + gain := sgr.Indicator.Calculate(index).Div(openPrice).Sub(big.ONE) + if record.currentPosition.IsShort() { + gain = gain.Neg() + } + return gain.GTE(sgr.tolerance) +} From cd2e5e75aac72eb3eedf3438dc5e9c091c50697e Mon Sep 17 00:00:00 2001 From: "huzhihao.navinfo.com" Date: Tue, 4 Dec 2018 09:08:55 +0800 Subject: [PATCH 4/9] adjust log format in LogTradesAnalysis Analyze --- analysis.go | 6 ++++-- order.go | 11 +++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/analysis.go b/analysis.go index c45c633..898c724 100644 --- a/analysis.go +++ b/analysis.go @@ -60,8 +60,10 @@ type LogTradesAnalysis struct { // Analyze logs trades to provided io.Writer func (lta LogTradesAnalysis) Analyze(record *TradingRecord) float64 { logOrder := func(trade *Position) { - fmt.Fprintln(lta.Writer, fmt.Sprintf("%s - enter with buy %s (%s @ $%s)", trade.EntranceOrder().ExecutionTime.UTC().Format(time.RFC822), trade.EntranceOrder().Security, trade.EntranceOrder().Amount, trade.EntranceOrder().Price)) - fmt.Fprintln(lta.Writer, fmt.Sprintf("%s - exit with sell %s (%s @ $%s)", trade.ExitOrder().ExecutionTime.UTC().Format(time.RFC822), trade.ExitOrder().Security, trade.ExitOrder().Amount, trade.ExitOrder().Price)) + fmt.Fprintln(lta.Writer, fmt.Sprintf("%s - enter with %s %s (%s @ $%s)", + trade.EntranceOrder().ExecutionTime.Format(time.RFC822), trade.EntranceOrder().Side, trade.EntranceOrder().Security, trade.EntranceOrder().Amount, trade.EntranceOrder().Price)) + fmt.Fprintln(lta.Writer, fmt.Sprintf("%s - exit with %s %s (%s @ $%s)", + trade.ExitOrder().ExecutionTime.Format(time.RFC822), trade.EntranceOrder().Side, trade.ExitOrder().Security, trade.ExitOrder().Amount, trade.ExitOrder().Price)) profit := trade.ExitValue().Sub(trade.CostBasis()) fmt.Fprintln(lta.Writer, fmt.Sprintf("Profit: $%s", profit)) diff --git a/order.go b/order.go index a8aedec..d824235 100644 --- a/order.go +++ b/order.go @@ -15,6 +15,17 @@ const ( SELL ) +func (os OrderSide) String() string { + switch os { + case BUY: + return "BUY" + case SELL: + return "SELL" + default: + return "UNKNOWN" + } +} + // Order represents a trade execution (buy or sell) with associated metadata. type Order struct { Side OrderSide From 77f27f7035218c59e74d085705593a388cccec05 Mon Sep 17 00:00:00 2001 From: "huzhihao.navinfo.com" Date: Tue, 4 Dec 2018 09:42:29 +0800 Subject: [PATCH 5/9] adjust profit calculation in LogTradesAnalysis Analyze --- analysis.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/analysis.go b/analysis.go index 898c724..5ab27fd 100644 --- a/analysis.go +++ b/analysis.go @@ -64,8 +64,12 @@ func (lta LogTradesAnalysis) Analyze(record *TradingRecord) float64 { trade.EntranceOrder().ExecutionTime.Format(time.RFC822), trade.EntranceOrder().Side, trade.EntranceOrder().Security, trade.EntranceOrder().Amount, trade.EntranceOrder().Price)) fmt.Fprintln(lta.Writer, fmt.Sprintf("%s - exit with %s %s (%s @ $%s)", trade.ExitOrder().ExecutionTime.Format(time.RFC822), trade.EntranceOrder().Side, trade.ExitOrder().Security, trade.ExitOrder().Amount, trade.ExitOrder().Price)) - - profit := trade.ExitValue().Sub(trade.CostBasis()) + profit := big.ZERO + if trade.IsLong() { + profit = trade.ExitValue().Sub(trade.CostBasis()) + } else { + profit = trade.CostBasis().Sub(trade.ExitValue()) + } fmt.Fprintln(lta.Writer, fmt.Sprintf("Profit: $%s", profit)) } From a86ee6ed19df9ac5c82506495d3d2d03b3fbb1fb Mon Sep 17 00:00:00 2001 From: glacier2002 Date: Tue, 4 Dec 2018 23:50:19 +0800 Subject: [PATCH 6/9] update total profit analysize --- analysis.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/analysis.go b/analysis.go index 5ab27fd..36d0934 100644 --- a/analysis.go +++ b/analysis.go @@ -24,8 +24,11 @@ func (tps TotalProfitAnalysis) Analyze(record *TradingRecord) float64 { if trade.IsClosed() { costBasis := trade.CostBasis() exitValue := trade.ExitValue() - - totalProfit = totalProfit.Add(exitValue.Sub(costBasis)) + if trade.IsLong() { + totalProfit = totalProfit.Add(exitValue.Sub(costBasis)) + } else { + totalProfit = totalProfit.Add(costBasis.Sub(exitValue)) + } } } From 1137a25ba8447e7082ec1f707324615be95393e1 Mon Sep 17 00:00:00 2001 From: glacier2002 Date: Thu, 13 Dec 2018 23:26:22 +0800 Subject: [PATCH 7/9] 1. fix bug in stop loss and adjust it with long/short order 2. add stop gain rule --- rule_stop.go | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/rule_stop.go b/rule_stop.go index 063840c..33d35fe 100644 --- a/rule_stop.go +++ b/rule_stop.go @@ -1,12 +1,19 @@ package techan -import "github.com/sdcoffey/big" +import ( + "github.com/sdcoffey/big" +) type stopLossRule struct { Indicator tolerance big.Decimal } +type stopGainRule struct { + Indicator + tolerance big.Decimal +} + // NewStopLossRule returns a new rule that is satisfied when the given loss tolerance (a percentage) is met or exceeded. // Loss tolerance should be a value between -1 and 1. func NewStopLossRule(series *TimeSeries, lossTolerance float64) Rule { @@ -20,8 +27,31 @@ func (slr stopLossRule) IsSatisfied(index int, record *TradingRecord) bool { if !record.CurrentPosition().IsOpen() { return false } - - openPrice := record.CurrentPosition().CostBasis() + openPrice := record.CurrentPosition().EntranceOrder().Price loss := slr.Indicator.Calculate(index).Div(openPrice).Sub(big.ONE) + if record.currentPosition.IsShort() { + loss = loss.Neg() + } return loss.LTE(slr.tolerance) } + +// NewStopLossRule returns a new rule that is satisfied when the given loss tolerance (a percentage) is met or exceeded. +// Loss tolerance should be a value between -1 and 1. +func NewStopGainRule(series *TimeSeries, gainTolerance float64) Rule { + return stopGainRule{ + Indicator: NewClosePriceIndicator(series), + tolerance: big.NewDecimal(gainTolerance), + } +} + +func (sgr stopGainRule) IsSatisfied(index int, record *TradingRecord) bool { + if !record.CurrentPosition().IsOpen() { + return false + } + openPrice := record.CurrentPosition().EntranceOrder().Price + gain := sgr.Indicator.Calculate(index).Div(openPrice).Sub(big.ONE) + if record.currentPosition.IsShort() { + gain = gain.Neg() + } + return gain.GTE(sgr.tolerance) +} From 6ebb3ef4052d1f2fc85b4603776a3249f72838bf Mon Sep 17 00:00:00 2001 From: beaquant <20572588+beaquant@users.noreply.github.com> Date: Fri, 8 Mar 2019 09:21:20 +0800 Subject: [PATCH 8/9] Update rule_stop.go --- rule_stop.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rule_stop.go b/rule_stop.go index 33d35fe..f827698 100644 --- a/rule_stop.go +++ b/rule_stop.go @@ -29,7 +29,7 @@ func (slr stopLossRule) IsSatisfied(index int, record *TradingRecord) bool { } openPrice := record.CurrentPosition().EntranceOrder().Price loss := slr.Indicator.Calculate(index).Div(openPrice).Sub(big.ONE) - if record.currentPosition.IsShort() { + if record.CurrentPosition().IsShort() { loss = loss.Neg() } return loss.LTE(slr.tolerance) @@ -50,7 +50,7 @@ func (sgr stopGainRule) IsSatisfied(index int, record *TradingRecord) bool { } openPrice := record.CurrentPosition().EntranceOrder().Price gain := sgr.Indicator.Calculate(index).Div(openPrice).Sub(big.ONE) - if record.currentPosition.IsShort() { + if record.CurrentPosition().IsShort() { gain = gain.Neg() } return gain.GTE(sgr.tolerance) From a7df3b2bd845780ddc1cd319784793e473c1d28f Mon Sep 17 00:00:00 2001 From: eric Date: Thu, 31 Oct 2019 16:59:42 +0800 Subject: [PATCH 9/9] adjust profit calculation in LogTradesAnalysis Analyze --- analysis.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/analysis.go b/analysis.go index 03b3528..d5c7205 100644 --- a/analysis.go +++ b/analysis.go @@ -70,12 +70,7 @@ func (lta LogTradesAnalysis) Analyze(record *TradingRecord) float64 { trade.EntranceOrder().ExecutionTime.Format(time.RFC822), trade.EntranceOrder().Side, trade.EntranceOrder().Security, trade.EntranceOrder().Amount, trade.EntranceOrder().Price)) fmt.Fprintln(lta.Writer, fmt.Sprintf("%s - exit with %s %s (%s @ $%s)", trade.ExitOrder().ExecutionTime.Format(time.RFC822), trade.EntranceOrder().Side, trade.ExitOrder().Security, trade.ExitOrder().Amount, trade.ExitOrder().Price)) - profit := big.ZERO - if trade.IsLong() { - profit = trade.ExitValue().Sub(trade.CostBasis()) - } else { - profit = trade.CostBasis().Sub(trade.ExitValue()) - } + profit := trade.ExitValue().Sub(trade.CostBasis()) fmt.Fprintln(lta.Writer, fmt.Sprintf("Profit: $%s", profit)) }