Skip to content

Commit

Permalink
Merge pull request #4 from evsamsonov/flat-max-diff-in-percent
Browse files Browse the repository at this point in the history
Trend: Flat max diff in percent
  • Loading branch information
evsamsonov committed Apr 8, 2023
2 parents 50fdb0f + fe17c1b commit 6347375
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 12 deletions.
13 changes: 13 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
name: golangci-lint
on:
push:
jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: golangci-lint
uses: golangci/golangci-lint-action@v2
with:
version: v1.52.2
21 changes: 21 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: test
on:
push:
jobs:
test:
strategy:
matrix:
platform: [ ubuntu-latest ]
runs-on: ${{ matrix.platform }}
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Install go
uses: actions/setup-go@v2
with:
go-version: '^1.15'
- name: Test
run: go test -gcflags='-N -l' -race -coverprofile=coverage.txt ./...
- name: Upload coverage to Codecov
run: bash <(curl -s https://codecov.io/bash)

19 changes: 19 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.PHONY: help lint test doc
.DEFAULT_GOAL := help

help:
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

pre-push: lint test ## Run golang lint and test

lint: ## Run golang lint using docker
go mod download
docker run --rm \
-v ${GOPATH}/pkg/mod:/go/pkg/mod \
-v ${PWD}:/app \
-w /app \
golangci/golangci-lint:v1.52.2 \
golangci-lint run -v --modules-download-mode=readonly

test: ## Run tests
go test ./...
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ fmt.Println(atrIndicator.Calculate(1)) // 22.84552

### Trend

The indicator returns a trend direction. It bases on fast (with shorter period) and slow EMA. The third parameter of NewTrend allows setting max difference between fast and slow EMA when Calculate returns the flat.
The indicator returns a trend direction. It bases on fast (with shorter period) and slow EMA. The third parameter (flatMaxDiff) of NewTrend allows setting max difference between fast and slow EMA when Calculate returns the flat. Option TrendWithFlatMaxDiffInPercent allows to pass flatMaxDiff in percent

```go
fastEMAIndicator, err := indicator.NewExponentialMovingAverage(series, 14)
Expand All @@ -88,7 +88,7 @@ if err != nil {
log.Fatalln(err)
}

trendIndicator := indicator.NewTrend(fastEMAIndicator, slowEMAIndicator, 0.6)
trendIndicator := indicator.NewTrend(fastEMAIndicator, slowEMAIndicator, 0.6, TrendWithFlatMaxDiffInPercent(false))
trend := trendIndicator.Calculate(1)
switch trend {
case indicator.UpTrend:
Expand Down
31 changes: 26 additions & 5 deletions indicator/trend.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,54 @@ const (
DownTrend float64 = -1
)

type TrendOption func(*Trend)

// TrendWithFlatMaxDiffInPercent allows to pass flatMaxDiff in percent.
// The default value is false
func TrendWithFlatMaxDiffInPercent(val bool) func(*Trend) {
return func(t *Trend) {
t.flatMaxDiffInPercent = val
}
}

// Trend returns a trend direction.
// It bases on fast (with shorter period) and slow EMA.
// flatMaxDiff allows setting max difference between
// fast and slow EMA when Calculate returns the flat.
type Trend struct {
fastEMAIndicator Indicator
slowEMAIndicator Indicator
flatMaxDiff float64
fastEMAIndicator Indicator
slowEMAIndicator Indicator
flatMaxDiff float64
flatMaxDiffInPercent bool
}

func NewTrend(
fastEMAIndicator Indicator,
slowEMAIndicator Indicator,
flatMaxDiff float64,
opts ...TrendOption,
) *Trend {
return &Trend{
trend := &Trend{
fastEMAIndicator: fastEMAIndicator,
slowEMAIndicator: slowEMAIndicator,
flatMaxDiff: flatMaxDiff,
}
for _, opt := range opts {
opt(trend)
}
return trend
}

func (t *Trend) Calculate(index int) float64 {
fastVal := t.fastEMAIndicator.Calculate(index)
slowVal := t.slowEMAIndicator.Calculate(index)

if math.Abs(fastVal-slowVal)-t.flatMaxDiff <= 1e-6 {
flatMaxDiff := t.flatMaxDiff
if t.flatMaxDiffInPercent {
flatMaxDiff = slowVal * t.flatMaxDiff / 100
}

if math.Abs(fastVal-slowVal)-flatMaxDiff <= 1e-6 {
return FlatTrend
}
if fastVal > slowVal {
Expand Down
30 changes: 25 additions & 5 deletions indicator/trend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import (

func TestTrend_Calculate(t *testing.T) {
tests := []struct {
name string
fastVal float64
slowVal float64
want float64
name string
fastVal float64
slowVal float64
flatMaxDiffInPercent bool
want float64
}{
{
name: "up trend",
Expand All @@ -37,14 +38,33 @@ func TestTrend_Calculate(t *testing.T) {
slowVal: 1.0,
want: FlatTrend,
},
{
name: "flat trend, diff in percent",
fastVal: 100.5,
slowVal: 100,
flatMaxDiffInPercent: true,
want: FlatTrend,
},
{
name: "up trend, diff in percent",
fastVal: 100.7,
slowVal: 100,
flatMaxDiffInPercent: true,
want: UpTrend,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
slowEMAIndicator := &MockIndicator{}
fastEMAIndicator := &MockIndicator{}

ind := NewTrend(fastEMAIndicator, slowEMAIndicator, 0.6)
ind := NewTrend(
fastEMAIndicator,
slowEMAIndicator,
0.6,
TrendWithFlatMaxDiffInPercent(tt.flatMaxDiffInPercent),
)
fastEMAIndicator.On("Calculate", 1).Return(tt.fastVal)
slowEMAIndicator.On("Calculate", 1).Return(tt.slowVal)

Expand Down

0 comments on commit 6347375

Please sign in to comment.