forked from mamady/gobacktest
-
Notifications
You must be signed in to change notification settings - Fork 0
/
moving-average-cross.go
65 lines (53 loc) · 1.96 KB
/
moving-average-cross.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package strategy
import (
"fmt"
bt "github.com/dirkolbrich/gobacktest/pkg/backtest"
)
// MovingAverageCross is a test strategy, which interprets the SMA on a series of data events
// specified by ShortWindow (SW) and LongWindow (LW).
// If SW bigger tha LW and there is not already an invested BOT position, the strategy creates a buy signal.
// If SW falls below LW and there is an invested BOT position, the strategy creates an exit signal.
type MovingAverageCross struct {
ShortWindow int
LongWindow int
}
// CalculateSignal handles the single Event
func (s *MovingAverageCross) CalculateSignal(e bt.DataEventHandler, data bt.DataHandler, p bt.PortfolioHandler) (bt.SignalEvent, error) {
// create empty Signal
se := &bt.Signal{}
// type switch for event type
switch e := e.(type) {
case *bt.Bar:
// calculate and set SMA for short window
smaShort, err := bt.CalculateSMA(s.ShortWindow, data.List(e.GetSymbol()))
if err != nil {
return se, err
}
e.Metrics[fmt.Sprintf("SMA%d", s.ShortWindow)] = smaShort
// calculate and set SMA for long window
smaLong, err := bt.CalculateSMA(s.LongWindow, data.List(e.GetSymbol()))
if err != nil {
return se, err
}
e.Metrics[fmt.Sprintf("SMA%d", s.LongWindow)] = smaLong
// check if already invested
_, invested := p.IsInvested(e.GetSymbol())
if (smaShort > smaLong) && invested {
return se, fmt.Errorf("buy signal but already invested in %v, no signal created,", e.GetSymbol())
}
if (smaShort > smaLong) && !invested {
// buy signal, populate the signal event
se.Event = bt.Event{Timestamp: e.GetTime(), Symbol: e.GetSymbol()}
se.Direction = "long"
}
if (smaShort <= smaLong) && !invested {
return se, fmt.Errorf("sell signal but not invested in %v, no signal created,", e.GetSymbol())
}
if (smaShort <= smaLong) && invested {
// sell signal, populate the signal event
se.Event = bt.Event{Timestamp: e.GetTime(), Symbol: e.GetSymbol()}
se.Direction = "exit"
}
}
return se, nil
}