gotrader

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 30, 2024 License: MIT Imports: 18 Imported by: 1

README

go-trader

build status

go-trader is a platform to backtest and run live trading strategies, with focus on intra-day trading.

Examples

Check out the examples!

Create a simple strategy

The full souce code for this example is in examples/backtest/main.go Import gotrader in your project

go get -v github.com/totomz/gotrader

Then write a simple strategy

package main
import "github.com/totomz/gotrader/gotrader"

type SimpleStrategy struct {
	broker gotrader.Broker
}

func (s *SimpleStrategy) Initialize(cerbero *gotrader.Cerbero) {
	s.broker = cerbero.Broker
}

func (s *SimpleStrategy) Eval(candles []gotrader.Candle) {
	// c is the latest candle
	c := candles[len(candles)-1]
	println(c.String())
}

Data Visualization

Backtestsing

Candles and indicators are saved in Signals, that can be exported in a JSON format once the simulation is done

dataGrafana := gotrader.SignalsToGrafana()
err = os.WriteFile("./plotly/signals_grafana.json", dataGrafana, 0644)
if err != nil {
    panic(err)
}

This file can be used to plot candles and indicators in Grafana

TODO:

  • Visualizzo la roba su grafana
  • BONUS: mi creo con le label "buy" and "sell"

Credits

Backtrader

go-trader is heavily inspired by Backtrader

Indicators

The indicators are based on github.com/cinar/indicator

Development

shMake is required to build and run the testss

Documentation

Index

Constants

View Source
const (
	OrderBuy = iota
	OrderSell
)
View Source
const (
	OrderStatusSubmitted = iota
	OrderStatusAccepted
	OrderStatusPartiallyFilled
	OrderStatusFullFilled
	OrderStatusRejected
)

Variables

View Source
var (
	ErrOrderNotFound = errors.New("order not found")
	ErrInvalidSize   = errors.New("order.size should be > 0")
)
View Source
var (
	MetricActivePosition = NewMetricWithDefaultViews("broker_position")
	BrockerPosition      = NewMetricWithDefaultViews("broker")

	// Stdout is used to log everything that is not considered an error
	Stdout = log.New(os.Stdout, "", log.Lshortfile|log.Ltime)
	// Stderr log errors that need attention
	Stderr = log.New(os.Stderr, "[ERROR]", log.Lmsgprefix|log.Lshortfile|log.Ltime)
)
View Source
var (
	ErrMetricNotFound = errors.New("metric not founc")

	MCandleOpen   = NewMetricWithDefaultViews("candle_open")
	MCandleHigh   = NewMetricWithDefaultViews("candle_high")
	MCandleClose  = NewMetricWithDefaultViews("candle_close")
	MCandleLow    = NewMetricWithDefaultViews("candle_low")
	MCandleVolume = NewMetricWithDefaultViews("candle_volume")
	MTradesBuy    = NewMetricWithDefaultViews("trades_buy")
	MTradesSell   = NewMetricWithDefaultViews("trades_sell")
	MCash         = NewMetricWithDefaultViews("cash")
	MStartingCash = NewMetricWithDefaultViews("cash_initial")
	MPosition     = NewMetricWithDefaultViews("position")

	KeySymbol, _ = tag.NewKey("symbol")
)
View Source
var Nocommissions = func(order Order, price float64) float64 { return 0 }

Functions

func Close

func Close(candles []Candle) []float64

func DefaultViewToName

func DefaultViewToName(vd *view.Data, row *view.Row) string

func GetNewContextFromCandle

func GetNewContextFromCandle(c Candle) context.Context

func High

func High(candles []Candle) []float64

func Low

func Low(candles []Candle) []float64

func NoAggregation

func NoAggregation(inputCandleChan <-chan Candle) <-chan AggregatedCandle

func Open

func Open(candles []Candle) []float64

func RandUid

func RandUid() string

func RegisterViews

func RegisterViews(views ...*view.View)

RegisterViews register the Opencensus views and enable the internal TimeSeries collection

func SameTime

func SameTime(a time.Time, hour, minute, seconds int) bool

func StopAt

func StopAt(c Candle, hour, min, sec int) bool

StopAt is a usefull function for debug a strategy. Returns true if the time of the candle match the given one

Types

type AggregatedCandle

type AggregatedCandle struct {
	Original         Candle
	AggregatedCandle Candle
	IsAggregated     bool
}

type BacktestBrocker

type BacktestBrocker struct {
	BrokerAvailableCash float64
	OrderMap            map[string]*Order
	Portfolio           map[Symbol]Position
	EvalCommissions     EvaluateCommissions
}

BacktestBrocker is the default broker to back-test a strategy

func (*BacktestBrocker) AvailableCash

func (b *BacktestBrocker) AvailableCash() float64

func (*BacktestBrocker) ClosePosition

func (b *BacktestBrocker) ClosePosition(position Position) error

ClosePosition @deprecated

func (*BacktestBrocker) GetOrderByID

func (b *BacktestBrocker) GetOrderByID(orderID string) (Order, error)

func (*BacktestBrocker) GetPosition

func (b *BacktestBrocker) GetPosition(symbol Symbol) Position

func (*BacktestBrocker) GetPositions

func (b *BacktestBrocker) GetPositions() []Position

func (*BacktestBrocker) ProcessOrders

func (b *BacktestBrocker) ProcessOrders(candle Candle) []Order

func (*BacktestBrocker) Shutdown

func (b *BacktestBrocker) Shutdown()

func (*BacktestBrocker) SubmitOrder

func (b *BacktestBrocker) SubmitOrder(_ Candle, order Order) (string, error)

type Broker

type Broker interface {
	SubmitOrder(candle Candle, order Order) (string, error)
	GetOrderByID(OrderID string) (Order, error)
	ProcessOrders(candle Candle) []Order
	GetPosition(symbol Symbol) Position
	Shutdown()
	AvailableCash() float64
	ClosePosition(position Position) error
	GetPositions() []Position
}

Broker interacts with a stock broker

type Candle

type Candle struct {
	Open   float64
	High   float64
	Close  float64
	Low    float64
	Volume int64
	Symbol Symbol
	Time   time.Time
}

func ZigZag

func ZigZag(candles []Candle) []Candle

func (Candle) String

func (candle Candle) String() string

func (Candle) TimeStr

func (candle Candle) TimeStr() string

type Cerbero

type Cerbero struct {
	Broker              Broker
	Strategy            Strategy
	DataFeed            DataFeed
	TimeAggregationFunc TimeAggregation
	// contains filtered or unexported fields
}

Cerbero is in honor to https://www.backtrader.com/ that deeply inspired this code

func (*Cerbero) Run

func (cerbero *Cerbero) Run() (ExecutionResult, error)

type DataFeed

type DataFeed interface {

	// Run starts a go routine that poll the data source, and push the candles in the returned channel.
	// The channel is expected to have a buffer larger enough to handle 1 day of data
	Run() (chan Candle, error)
}

DataFeed provides a stream of Candle.

type EvaluateCommissions

type EvaluateCommissions func(order Order, price float64) float64

type ExecutionResult

type ExecutionResult struct {
	TotalTime       time.Duration `json:"total_time"`
	TotalTimeString string        `json:"total_time_S"`
	InitialCash     float64       `json:"initial_cash"`
	PL              float64       `json:"pl"`
	FinalCash       float64       `json:"final_cash"`
}

type IBZippedCSV

type IBZippedCSV struct {
	DataFolder string
	Sday       time.Time
	Slowtime   time.Duration
	Symbol     Symbol
	Symbols    []Symbol
}

func (*IBZippedCSV) Run

func (d *IBZippedCSV) Run() (chan Candle, error)

type MemorySignals

type MemorySignals struct {
	Metrics map[string]*TimeSerie
}

func (*MemorySignals) Append

func (s *MemorySignals) Append(candle Candle, name string, value float64)

Append a metric to a given signal.

func (*MemorySignals) Get

func (s *MemorySignals) Get(candle Candle, name string, i int) (float64, error)

type Metric

type Metric struct {
	Name string
	// contains filtered or unexported fields
}

func NewMetricWithDefaultViews

func NewMetricWithDefaultViews(name string) *Metric

func (*Metric) Get

func (m *Metric) Get(ctx context.Context, step int) (float64, error)

Get the i-th metric. Metrics are saved in their chronological order. m.Get(0) returns the last value recorder by the metric m. m.Get(-3) return the value inserted 3 "step" ago. A step is defined as a full eval() cycle.

func (*Metric) Record

func (m *Metric) Record(ctx context.Context, value float64)

func (*Metric) RecordBatch

func (m *Metric) RecordBatch(candles []Candle, value float64)

type Order

type Order struct {
	Id string
	// Size is always > 0
	Size   int64
	Symbol Symbol
	Type   OrderType
	Status OrderStatus
	// SizeFilled is always > 0
	SizeFilled     int64
	AvgFilledPrice float64

	// SubmittedTime When the order has been submitted (candle time)
	SubmittedTime time.Time
}

func (Order) String

func (o Order) String() string

type OrderStatus

type OrderStatus int

type OrderType

type OrderType int

type Position

type Position struct {
	// Size is negative if the position is a SHORT
	Size     int64
	AvgPrice float64
	Symbol   Symbol
}

type RedisExporter

type RedisExporter struct {
	// MetricNameGenerator MUST return a string formatted as `gotrader.<symbol>.<metric>`
	MetricNameGenerator func(vd *view.Data, row *view.Row) string
	// contains filtered or unexported fields
}

func NewRedisExporter

func NewRedisExporter(redisHostPort string) (*RedisExporter, error)

func (RedisExporter) ExportView

func (exp RedisExporter) ExportView(vd *view.Data)

func (RedisExporter) Flush

func (exp RedisExporter) Flush()

func (RedisExporter) FlushBuffer

func (exp RedisExporter) FlushBuffer(path string)

FlushBuffer saves the commands in a .redis file, that can be imported later

type SimplePsarStrategy

type SimplePsarStrategy struct {
	Symbol Symbol
}

func (*SimplePsarStrategy) Eval

func (s *SimplePsarStrategy) Eval(candles []Candle)

func (*SimplePsarStrategy) Initialize

func (s *SimplePsarStrategy) Initialize(_ *Cerbero)

type Strategy

type Strategy interface {
	// Eval evaluate the strategy. candles[0] is the latest, candles[1] is the latest - 1, and so on
	Eval(candles []Candle)
	Initialize(broker *Cerbero)
	// Shutdown is called by Cerbero when there are no more incoming candles.
	Shutdown()
}

type Symbol

type Symbol string

type TimeAggregation

type TimeAggregation func(<-chan Candle) <-chan AggregatedCandle

TimeAggregation aggregate the candles from a channel and write the output in a separate channel

func AggregateBySeconds

func AggregateBySeconds(sec int) TimeAggregation

type TimeSerie

type TimeSerie struct {
	X []time.Time `json:"x"`
	Y []float64   `json:"y"`
}

func (*TimeSerie) Append

func (ts *TimeSerie) Append(candle Candle, value float64)

Append an element to the end of this ts

type ZigZagStrategy

type ZigZagStrategy struct {
}

Directories

Path Synopsis
cmd
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL