forked from c9s/bbgo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request c9s#505 from zenixls2/feature/series
feature: add pinescript series interface
- Loading branch information
Showing
18 changed files
with
1,012 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
How To Use Builtin Indicators and Create New Indicators | ||
------------------------------------------------------- | ||
|
||
### Built-in Indicators | ||
In bbgo session, we already have several indicators defined inside. | ||
We could refer to the live-data without the worriedness of handling market data subscription. | ||
To use the builtin ones, we could refer the `StandardIndicatorSet` type: | ||
|
||
```go | ||
// defined in pkg/bbgo/session.go | ||
(*StandardIndicatorSet) BOLL(iw types.IntervalWindow, bandwidth float64) *indicator.BOLL | ||
(*StandardIndicatorSet) SMA(iw types.IntervalWindow) *indicator.SMA | ||
(*StandardIndicatorSet) EWMA(iw types.IntervalWindow) *indicator.EWMA | ||
(*StandardIndicatorSet) STOCH(iw types.IntervalWindow) *indicator.STOCH | ||
(*StandardIndicatorSet) VOLATILITY(iw types.IntervalWindow) *indicator.VOLATILITY | ||
``` | ||
|
||
and to get the `*StandardIndicatorSet` from `ExchangeSession`, just need to call: | ||
```go | ||
indicatorSet, ok := session.StandardIndicatorSet("BTCUSDT") // param: symbol | ||
``` | ||
in your strategy's `Run` function. | ||
|
||
|
||
And in `Subscribe` function in strategy, just subscribe the `KLineChannel` on the interval window of the indicator you want to query, you should be able to acquire the latest number on the indicators. | ||
|
||
However, what if you want to use the indicators not defined in `StandardIndicatorSet`? For example, the `AD` indicator defined in `pkg/indicators/ad.go`? | ||
|
||
Here's a simple example in what you should write in your strategy code: | ||
```go | ||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/c9s/bbgo/pkg/bbgo" | ||
"github.com/c9s/bbgo/pkg/types" | ||
"github.com/c9s/bbgo/pkg/indicator" | ||
) | ||
|
||
type Strategy struct {} | ||
|
||
func (s *Strategy) Subscribe(session *bbgo.ExchangeSession) { | ||
session.Subscribe(types.KLineChannel, s.Symbol. types.SubscribeOptions{Interval: "1m"}) | ||
} | ||
|
||
func (s *Strategy) Run(ctx context.Context, oe bbgo.OrderExecutor, session *bbgo.ExchangeSession) error { | ||
// first we need to get market data store(cached market data) from the exchange session | ||
st, ok := session.MarketDataStore(s.Symbol) | ||
if !ok { | ||
... | ||
return err | ||
} | ||
// setup the time frame size | ||
window := types.IntervalWindow{Window: 10, Interval: types.Interval1m} | ||
// construct AD indicator | ||
AD := &indicator.AD{IntervalWindow: window} | ||
// bind indicator to the data store, so that our callback could be triggered | ||
AD.Bind(st) | ||
AD.OnUpdate(func (ad float64) { | ||
fmt.Printf("now we've got ad: %f, total length: %d\n", ad, AD.Length()) | ||
}) | ||
} | ||
``` | ||
|
||
#### To Contribute | ||
|
||
try to create new indicators in `pkg/indicator/` folder, and add compilation hint of go generator: | ||
```go | ||
// go:generate callbackgen -type StructName | ||
type StructName struct { | ||
... | ||
UpdateCallbacks []func(value float64) | ||
} | ||
|
||
``` | ||
And implement required interface methods: | ||
```go | ||
// custom function | ||
func (inc *StructName) calculateAndUpdate(kLines []types.KLine) { | ||
// calculation... | ||
// assign the result to calculatedValue | ||
inc.EmitUpdate(calculatedValue) // produce data, broadcast to the subscribers | ||
} | ||
|
||
// custom function | ||
func (inc *StructName) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) { | ||
// filter on interval | ||
inc.calculateAndUpdate(window) | ||
} | ||
|
||
// required | ||
func (inc *StructName) Bind(updator KLineWindowUpdater) { | ||
updater.OnKLineWindowUpdate(inc.handleKLineWindowUpdate) | ||
} | ||
``` | ||
|
||
The `KLineWindowUpdater` interface is currently defined in `pkg/indicator/ewma.go` and may be moved out in the future. | ||
|
||
Once the implementation is done, run `go generate` to generate the callback functions of the indicator. | ||
You should be able to implement your strategy and use the new indicator in the same way as `AD`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package indicator | ||
|
||
import ( | ||
"time" | ||
|
||
"github.com/c9s/bbgo/pkg/types" | ||
) | ||
|
||
// Line indicator is a utility that helps to simulate either the | ||
// 1. trend | ||
// 2. support | ||
// 3. resistance | ||
// of the market data, defined with series interface | ||
type Line struct { | ||
types.IntervalWindow | ||
start float64 | ||
end float64 | ||
startIndex int | ||
endIndex int | ||
currentTime time.Time | ||
Interval types.Interval | ||
} | ||
|
||
func (l *Line) handleKLineWindowUpdate(interval types.Interval, window types.KLineWindow) { | ||
if interval != l.Interval { | ||
return | ||
} | ||
newTime := window.Last().EndTime.Time() | ||
delta := int(newTime.Sub(l.currentTime).Minutes()) / l.Interval.Minutes() | ||
l.startIndex += delta | ||
l.endIndex += delta | ||
l.currentTime = newTime | ||
} | ||
|
||
func (l *Line) Bind(updater KLineWindowUpdater) { | ||
updater.OnKLineWindowUpdate(l.handleKLineWindowUpdate) | ||
} | ||
|
||
func (l *Line) Last() float64 { | ||
return (l.end-l.start) / float64(l.startIndex - l.endIndex) * float64(l.endIndex) + l.end | ||
} | ||
|
||
func (l *Line) Index(i int) float64 { | ||
return (l.end-l.start) / float64(l.startIndex - l.endIndex) * float64(l.endIndex - i) + l.end | ||
} | ||
|
||
func (l *Line) Length() int { | ||
if l.startIndex > l.endIndex { | ||
return l.startIndex - l.endIndex | ||
} else { | ||
return l.endIndex - l.startIndex | ||
} | ||
} | ||
|
||
func (l *Line) SetXY1(index int, value float64) { | ||
l.startIndex = index | ||
l.start = value | ||
} | ||
|
||
func (l *Line) SetXY2(index int, value float64) { | ||
l.endIndex = index | ||
l.end = value | ||
} | ||
|
||
func NewLine(startIndex int, startValue float64, endIndex int, endValue float64, interval types.Interval) *Line { | ||
return &Line{ | ||
start: startValue, | ||
end: endValue, | ||
startIndex: startIndex, | ||
endIndex: endIndex, | ||
currentTime: time.Time{}, | ||
Interval: interval, | ||
} | ||
} | ||
|
||
var _ types.Series = &Line{} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.