autotrader

package module
v0.0.0-...-9ccfdb4 Latest Latest
Warning

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

Go to latest
Published: May 17, 2025 License: 0BSD Imports: 23 Imported by: 0

README

autotrader

[WARNING]: There are still many bugs to be fixed, this software is not ready to be used for live trading. PRs and bug fixes welcome!

If you still feel like importing the library into your project, I highly recommend vendoring it (copying it directly to the folder).

Autotrader is a forex quantitative trading engine I developed in two weeks using Go. The unique backtesting simulations runs a user-designed trading algorithm against historical market data. The simulation accounts for brokerage fees, hedging, leverage, market orders, limit orders, stop orders, and more. Once a reliable strategy has been identified, the user can run the trading algorithm they created on their live brokerage account.

Autotrader inserts layers of abstraction all the way down from the implementation of the trading strategy to the orders and positions maintained by the brokers over their JSON REST APIs. All financial algorithms and data structures used in this project were developed from scratch, including a time series table inspired by the NumPy Python data science library.

The following page is a report generated by Autotrader when backtesting a naive SMA crossover strategy using realtime Forex market data:

Graph of live trades as executed by the strategy.

Return on investment of the strategy plotted over time.

Profitability graph of the strategy.

License

Zero-clause BSD (0BSD)

Documentation

Index

Constants

View Source
const (
	CloseMarket       OrderCloseType = "M"
	CloseStopLoss     OrderCloseType = "SL"
	CloseTrailingStop OrderCloseType = "TS"
	CloseTakeProfit   OrderCloseType = "TP"

	OrderPlaced    = "OrderPlaced"
	OrderCancelled = "OrderCancelled"
	OrderFulfilled = "OrderFulfilled"

	PositionClosed = "PositionClosed"
)

Variables

View Source
var (
	ErrEOF            = errors.New("end of the input data")
	ErrNoData         = errors.New("no data")
	ErrPositionClosed = errors.New("position already closed")
	ErrInvalidUnits   = errors.New("the units provided failed to meet the criteria")
)
View Source
var (
	ErrCancelFailed      = errors.New("cancel failed")
	ErrSymbolNotFound    = errors.New("symbol not found")
	ErrInvalidStopLoss   = errors.New("invalid stop loss")
	ErrInvalidTakeProfit = errors.New("invalid take profit")
)
View Source
var ErrNotASignedNumber = errors.New("not a signed number")

Functions

func Abs

func Abs[T constraints.Integer | constraints.Float](a T) T

func Backtest

func Backtest(trader *Trader)

func Crossover

func Crossover(a, b *Series) bool

Crossover returns true if the latest a value crosses above the latest b value, but only if it just happened. For example, if a series is [1, 2, 3, 4, 5] and b series is [1, 2, 3, 4, 3], then Crossover(a, b) returns false because the latest a value is 5 and the latest b value is 3. However, if a series is [1, 2, 3, 4, 5] and b series is [1, 2, 3, 4, 6], then Crossover(a, b) returns true because the latest a value is 5 and the latest b value is 6

func CrossoverIndex

func CrossoverIndex[I Index](index I, a, b *IndexedSeries[I]) bool

CrossoverIndex is similar to Crossover, except that it works for IndexedSeries.

func EasyIndex

func EasyIndex(i, n int) int

EasyIndex returns an index to the `n` -length object that allows for negative indexing. For example, EasyIndex(-1, 5) returns 4. This is similar to Python's negative indexing. The return value may be less than zero if (-i) > n.

func EqualApprox

func EqualApprox(a, b float64) bool

EqualApprox returns true if a and b are approximately equal. NaN and Inf are handled correctly. The tolerance is 1e-6 or 0.0000001.

func LessAny

func LessAny(a, b any) (less bool, offender any)

LessAny returns true if a < b. a and b must be signed numbers. If a or b is not a signed number, then the function returns false, and the value that was first identified as not a signed number as the interface{} alias 'any'. The order of checking is a -> b. If a is not a signed number, then a is returned as the offender. Else if b is not a signed number, then b is returned as the offender. Else, nil is returned as the offender.

A signed number is any of the following types:

  • float64
  • float32
  • int
  • int64
  • int32
  • int16
  • int8

func LeverageToMargin

func LeverageToMargin(leverage float64) float64

func MarginToLeverage

func MarginToLeverage(margin float64) float64

func Max

func Max[T constraints.Ordered](a, b T) T

func Min

func Min[T constraints.Ordered](a, b T) T

func Open

func Open(url string) error

Open opens the specified URL in the default browser of the user.

func Round

func Round(f float64, d int) float64

Round returns f rounded to d decimal places. d may be negative to round to the left of the decimal point.

Examples:

Round(123.456, 0) // 123.0
Round(123.456, 1) // 123.5
Round(123.456, -1) // 120.0

func UnixTimeStep

func UnixTimeStep(frequency time.Duration) func(UnixTime, int) UnixTime

UnixTimeStep returns a function that adds a number of increments to a UnixTime.

Types

type Broker

type Broker interface {
	Signaler
	Price(symbol string, wantToBuy bool) float64 // Price returns the ask price if wantToBuy is true and the bid price if wantToBuy is false.
	Bid(symbol string) float64                   // Bid returns the sell price of the symbol.
	Ask(symbol string) float64                   // Ask returns the buy price of the symbol, which is typically higher than the sell price.
	// Candles returns a dataframe of candles for the given symbol, frequency, and count by querying the broker.
	Candles(symbol, frequency string, count int) (*IndexedFrame[UnixTime], error)
	// Order places an order with orderType for the given symbol and returns an error if it fails. A short position has negative units. If the orderType is Market, the price argument will be ignored and the order will be fulfilled at current price. Otherwise, price is used to set the target price for Stop and Limit orders. If stopLoss or takeProfit are zero, they will not be set. If the stopLoss is greater than the current price for a long position or less than the current price for a short position, the order will fail. Likewise for takeProfit. If the stopLoss is a negative number, it is used as a trailing stop loss to represent how many price points away the stop loss should be from the current price.
	Order(orderType OrderType, symbol string, units, price, stopLoss, takeProfit float64) (Order, error)
	NAV() float64 // NAV returns the net asset value of the account.
	PL() float64  // PL returns the profit or loss of the account.
	OpenOrders() []Order
	OpenPositions() []Position
	// Orders returns a slice of orders that have been placed with the broker. If an order has been canceled or
	// filled, it will not be returned.
	Orders() []Order
	// Positions returns a slice of positions that are currently open with the broker. If a position has been
	// closed, it will not be returned.
	Positions() []Position
}

Broker is an interface that defines the methods that a broker must implement to report symbol data and place orders, etc. All Broker implementations must also implement the Signaler interface and emit the following functions when necessary:

  • PositionClosed(Position) - Emitted after a position is closed either manually or automatically.

type ErrIndexExists

type ErrIndexExists struct {
	// contains filtered or unexported fields
}

func (ErrIndexExists) Error

func (e ErrIndexExists) Error() string

type FloatSeries

type FloatSeries struct {
	*Series // The underlying Series which contains the data. Accessing this directly will not provide the type safety of FloatSeries and may cause panics.
}

FloatSeries is a wrapper of a Series where all items are float64 values. This is done by always casting values to and from float64

func NewFloatSeries

func NewFloatSeries(name string, vals ...float64) *FloatSeries

func RSI

func RSI(series *FloatSeries, periods int) *FloatSeries

RSI calculates the Relative Strength Index for a given Series. Typically, the input series is the Close column of a DataFrame. Returns a Series of RSI values of the same length as the input.

Traditionally, an RSI reading of 70 or above indicates an overbought condition, and a reading of 30 or below indicates an oversold condition.

Typically, the RSI is calculated with a period of 14 days.

func (*FloatSeries) Add

func (s *FloatSeries) Add(other *FloatSeries) *FloatSeries

func (*FloatSeries) Copy

func (s *FloatSeries) Copy() *FloatSeries

func (*FloatSeries) CopyRange

func (s *FloatSeries) CopyRange(start, count int) *FloatSeries

func (*FloatSeries) Div

func (s *FloatSeries) Div(other *FloatSeries) *FloatSeries

func (*FloatSeries) Filter

func (s *FloatSeries) Filter(f func(i int, val float64) bool) *FloatSeries

func (*FloatSeries) ForEach

func (s *FloatSeries) ForEach(f func(i int, val float64))

func (*FloatSeries) Map

func (s *FloatSeries) Map(f func(i int, val float64) float64) *FloatSeries

func (*FloatSeries) MapReverse

func (s *FloatSeries) MapReverse(f func(i int, val float64) float64) *FloatSeries

func (*FloatSeries) Max

func (s *FloatSeries) Max() float64

Max returns the maximum value in the series or 0 if the series is empty. This should be used over Series.MaxFloat() because this function contains optimizations that assume all the values are of float64.

func (*FloatSeries) Min

func (s *FloatSeries) Min() float64

Min returns the minimum value in the series or 0 if the series is empty. This should be used over Series.MinFloat() because this function contains optimizations that assume all the values are of float64.

func (*FloatSeries) Mul

func (s *FloatSeries) Mul(other *FloatSeries) *FloatSeries

func (*FloatSeries) Pop

func (s *FloatSeries) Pop() float64

func (*FloatSeries) Push

func (s *FloatSeries) Push(val float64) *FloatSeries

func (*FloatSeries) Remove

func (s *FloatSeries) Remove(i int) float64

Remove deletes the value at the given index and returns it. If the index is out of bounds, it returns 0.

func (*FloatSeries) RemoveRange

func (s *FloatSeries) RemoveRange(start, count int) *FloatSeries

func (*FloatSeries) Reverse

func (s *FloatSeries) Reverse() *FloatSeries

func (*FloatSeries) SetName

func (s *FloatSeries) SetName(name string) *FloatSeries

func (*FloatSeries) SetValue

func (s *FloatSeries) SetValue(i int, val float64) *FloatSeries

func (*FloatSeries) Sub

func (s *FloatSeries) Sub(other *FloatSeries) *FloatSeries

func (*FloatSeries) Value

func (s *FloatSeries) Value(i int) float64

func (*FloatSeries) ValueRange

func (s *FloatSeries) ValueRange(start, count int) []float64

func (*FloatSeries) Values

func (s *FloatSeries) Values() []float64

type Frame

type Frame struct {
	// contains filtered or unexported fields
}

func NewDOHLCVFrame

func NewDOHLCVFrame() *Frame

NewDOHLCVFrame returns a Frame with empty Date, Open, High, Low, Close, and Volume columns. Use the PushCandle method to add candlesticks in an easy and type-safe way.

func NewFrame

func NewFrame(series ...*Series) *Frame

func (*Frame) Close

func (d *Frame) Close(i int) float64

Close returns the close price of the candle at index i. i is an EasyIndex. If i is out of bounds, 0 is returned. This is the equivalent to calling Float("Close", i).

func (*Frame) Closes

func (d *Frame) Closes() *FloatSeries

Closes returns a FloatSeries of all the close prices in the Frame. This is equivalent to calling Series("Close").

func (*Frame) Contains

func (d *Frame) Contains(names ...string) bool

Contains returns true if the Frame contains all the given series names. Remember that names are case sensitive.

func (*Frame) ContainsDOHLCV

func (d *Frame) ContainsDOHLCV() bool

ContainsDOHLCV returns true if the Frame contains the series "Date", "Open", "High", "Low", "Close", and "Volume". This is equivalent to calling Contains("Date", "Open", "High", "Low", "Close", "Volume").

func (*Frame) Copy

func (d *Frame) Copy() *Frame

Copy is the same as CopyRange(0, -1)

func (*Frame) CopyRange

func (d *Frame) CopyRange(start, count int) *Frame

Copy returns a new Frame with a copy of the original series. start is an EasyIndex and count is the number of rows to copy from start onward. If count is negative then all rows from start to the end of the frame are copied. If there are not enough rows to copy then the maximum amount is returned. If there are no items to copy then a Frame will be returned with a length of zero but with the same column names as the original.

Examples:

Copy(0, 10) - copy the first 10 rows
Copy(-1, 1) - copy the last row
Copy(-10, -1) - copy the last 10 rows

func (*Frame) Date

func (d *Frame) Date(i int) time.Time

Date returns the value of the Date column at index i. i is an EasyIndex. If i is out of bounds, time.Time{} is returned. This is equivalent to calling Time("Date", i).

func (*Frame) Dates

func (d *Frame) Dates() *Series

Dates returns a Series of all the dates in the Frame. This is equivalent to calling Series("Date").

func (*Frame) Float

func (d *Frame) Float(column string, i int) float64

Float returns the float64 value of the column at index i. i is an EasyIndex. If i is out of bounds or the value was not a float64, then 0 is returned.

func (*Frame) High

func (d *Frame) High(i int) float64

High returns the high price of the candle at index i. i is an EasyIndex. If i is out of bounds, 0 is returned. This is the equivalent to calling Float("High", i).

func (*Frame) Highs

func (d *Frame) Highs() *FloatSeries

Highs returns a FloatSeries of all the high prices in the Frame. This is equivalent to calling Series("High").

func (*Frame) Int

func (d *Frame) Int(column string, i int) int

Int returns the int value of the column at index i. i is an EasyIndex. If i is out of bounds or the value was not an int, then 0 is returned.

func (*Frame) Len

func (d *Frame) Len() int

Len returns the number of rows in the Frame or 0 if the Frame has no rows. If the Frame has series of different lengths, then the longest length series is returned.

func (*Frame) Low

func (d *Frame) Low(i int) float64

Low returns the low price of the candle at index i. i is an EasyIndex. If i is out of bounds, 0 is returned. This is the equivalent to calling Float("Low", i).

func (*Frame) Lows

func (d *Frame) Lows() *FloatSeries

Lows returns a FloatSeries of all the low prices in the Frame. This is equivalent to calling Series("Low").

func (*Frame) Names

func (d *Frame) Names() []string

Names returns a slice of the names of the series in the Frame.

func (*Frame) Open

func (d *Frame) Open(i int) float64

Open returns the open price of the candle at index i. i is an EasyIndex. If i is out of bounds, 0 is returned. This is the equivalent to calling Float("Open", i).

func (*Frame) Opens

func (d *Frame) Opens() *FloatSeries

Opens returns a FloatSeries of all the open prices in the Frame. This is equivalent to calling Series("Open").

func (*Frame) PushCandle

func (d *Frame) PushCandle(date time.Time, open, high, low, close float64, volume int64) error

PushCandle pushes a candlestick to the Frame. If the Frame does not contain the series "Date", "Open", "High", "Low", "Close", and "Volume", an error is returned.

func (*Frame) PushSeries

func (d *Frame) PushSeries(series ...*Series) error

PushSeries adds the given series to the Frame. If the Frame already contains a series with the same name, an error is returned.

func (*Frame) PushValues

func (d *Frame) PushValues(values map[string]any) error

PushValues uses the keys of the values map as the names of the series to push the values to. If the Frame does not contain a series with a given name, an error is returned.

func (*Frame) RemoveSeries

func (d *Frame) RemoveSeries(names ...string)

RemoveSeries removes the given series from the Frame. If the Frame does not contain a series with a given name, nothing happens.

func (*Frame) Select

func (d *Frame) Select(names ...string) *Frame

Select returns a new Frame with the selected Series. The series are not copied so the returned frame will be a reference to the current frame. If a series name is not found, it is ignored.

func (*Frame) Series

func (d *Frame) Series(name string) *Series

Series returns a Series of the column with the given name. If the column does not exist, nil is returned.

func (*Frame) Str

func (d *Frame) Str(column string, i int) string

Str returns the string value of the column at index i. i is an EasyIndex. If i is out of bounds or the value was not a string, then the empty string "" is returned.

func (*Frame) String

func (d *Frame) String() string

String returns a string representation of the Frame. If the Frame is nil, it will return the string "*autotrader.Frame[nil]". Otherwise, it will return a string like:

	*autotrader.Frame[2x6]
	   Date        Open  High  Low  Close  Volume
	1  2019-01-01  1     2     3    4      5
    2  2019-01-02  4     5     6    7      8

The order of the columns is not defined.

If the Frame has more than 20 rows, the output will include the first ten rows and the last ten rows.

func (*Frame) Time

func (d *Frame) Time(column string, i int) time.Time

Time returns the time.Time value of the column at index i. i is an EasyIndex. If i is out of bounds or the value was not a Time, then time.Time{} is returned. Use Time.IsZero() to check if the value was valid.

func (*Frame) Value

func (d *Frame) Value(column string, i int) any

Value returns the value of the column at index i. i is an EasyIndex. If i is out of bounds, nil is returned.

func (*Frame) Volume

func (d *Frame) Volume(i int) int

Volume returns the volume of the candle at index i. i is an EasyIndex. If i is out of bounds, 0 is returned. This is the equivalent to calling Float("Volume", i).

func (*Frame) Volumes

func (d *Frame) Volumes() *FloatSeries

Volumes returns a Series of all the volumes in the Frame. This is equivalent to calling Series("Volume").

type Index

type Index interface {
	comparable
	constraints.Ordered
}

type IndexedFrame

type IndexedFrame[I Index] struct {
	*SignalManager
	// contains filtered or unexported fields
}

It is worth mentioning that if you want to use time.Time as an index type, then you should use the public UnixTime as a Unix int64 time which can be converted back into a time.Time easily. See time.Time(https://pkg.go.dev/time#Time) for more information on why you should not compare Time with == (or a map, which is what the IndexedFrame uses).

func Ichimoku

func Ichimoku(price *IndexedFrame[UnixTime], convPeriod, basePeriod, leadingPeriods int, frequency time.Duration) *IndexedFrame[UnixTime]

Ichimoku calculates the Ichimoku Cloud for a given Series. Returns a DataFrame of the same length as the input with float64 values. The series input must contain only float64 values, which are traditionally the close prices.

The standard values:

  • convPeriod: 9
  • basePeriod: 26
  • leadingPeriods: 52

DataFrame columns:

  • Conversion
  • Base
  • LeadingA
  • LeadingB
  • Lagging

func NewDOHLCVIndexedFrame

func NewDOHLCVIndexedFrame[I Index]() *IndexedFrame[I]

NewDOHLCVIndexedFrame returns a IndexedFrame with empty Date, Open, High, Low, Close, and Volume columns. Use the PushCandle method to add candlesticks in an easy and type-safe way.

It is worth mentioning that if you want to use time.Time as an index type, then you should use int64 as a Unix time. See time.Time(https://pkg.go.dev/time#Time) for more information on why you should not compare Time with == (or a map, which is what the IndexedFrame uses).

func NewIndexedFrame

func NewIndexedFrame[I Index](series ...*IndexedSeries[I]) *IndexedFrame[I]

It is worth mentioning that if you want to use time.Time as an index type, then you should use int64 as a Unix time. See time.Time(https://pkg.go.dev/time#Time) for more information on why you should not compare Time with == (or a map, which is what the IndexedFrame uses).

func (*IndexedFrame[I]) Close

func (f *IndexedFrame[I]) Close(i int) float64

Close returns the close price of the candle at index i. i is an EasyIndex. If i is out of bounds, 0 is returned. This is the equivalent to calling Float("Close", i).

func (*IndexedFrame[I]) CloseIndex

func (f *IndexedFrame[I]) CloseIndex(index I) float64

func (*IndexedFrame[I]) Closes

func (f *IndexedFrame[I]) Closes() *IndexedSeries[I]

Closes returns a FloatSeries of all the close prices in the IndexedFrame. This is equivalent to calling Series("Close").

func (*IndexedFrame[I]) Contains

func (f *IndexedFrame[I]) Contains(names ...string) bool

Contains returns true if the IndexedFrame contains all the given series names. Remember that names are case sensitive.

func (*IndexedFrame[I]) ContainsDOHLCV

func (f *IndexedFrame[I]) ContainsDOHLCV() bool

ContainsDOHLCV returns true if the IndexedFrame contains the series "Date", "Open", "High", "Low", "Close", and "Volume". This is equivalent to calling Contains("Date", "Open", "High", "Low", "Close", "Volume").

func (*IndexedFrame[I]) Copy

func (f *IndexedFrame[I]) Copy() *IndexedFrame[I]

Copy is the same as CopyRange(0, -1)

func (*IndexedFrame[I]) CopyRange

func (f *IndexedFrame[I]) CopyRange(start, count int) *IndexedFrame[I]

Copy returns a new IndexedFrame with a copy of the original series. start is an EasyIndex and count is the number of rows to copy from start onward. If count is negative then all rows from start to the end of the IndexedFrame are copied. If there are not enough rows to copy then the maximum amount is returned. If there are no items to copy then a IndexedFrame will be returned with a length of zero but with the same column names as the original.

Examples:

Copy(0, 10) - copy the first 10 rows
Copy(-1, 1) - copy the last row
Copy(-10, -1) - copy the last 10 rows

func (*IndexedFrame[I]) Date

func (f *IndexedFrame[I]) Date(i int) *I

Date returns the value of the Date column at index i. i is an EasyIndex. If i is out of bounds, time.Time{} is returned. This is equivalent to calling Index(i).

func (*IndexedFrame[I]) Float

func (f *IndexedFrame[I]) Float(column string, i int) float64

Float returns the float64 value of the column at index i. i is an EasyIndex. If i is out of bounds or the value was not a float64, then 0 is returned.

func (*IndexedFrame[I]) FloatIndex

func (f *IndexedFrame[I]) FloatIndex(column string, index I) float64

func (*IndexedFrame[I]) ForEachSeries

func (f *IndexedFrame[I]) ForEachSeries(fn func(*IndexedSeries[I]))

func (*IndexedFrame[I]) High

func (f *IndexedFrame[I]) High(i int) float64

High returns the high price of the candle at index i. i is an EasyIndex. If i is out of bounds, 0 is returned. This is the equivalent to calling Float("High", i).

func (*IndexedFrame[I]) HighIndex

func (f *IndexedFrame[I]) HighIndex(index I) float64

func (*IndexedFrame[I]) Highs

func (f *IndexedFrame[I]) Highs() *IndexedSeries[I]

Highs returns a FloatSeries of all the high prices in the IndexedFrame. This is equivalent to calling Series("High").

func (*IndexedFrame[I]) Index

func (f *IndexedFrame[I]) Index(row int) *I

func (*IndexedFrame[I]) Int

func (f *IndexedFrame[I]) Int(column string, i int) int

Int returns the int value of the column at index i. i is an EasyIndex. If i is out of bounds or the value was not an int, then 0 is returned.

func (*IndexedFrame[I]) IntIndex

func (f *IndexedFrame[I]) IntIndex(column string, index I) int

func (*IndexedFrame[I]) Len

func (f *IndexedFrame[I]) Len() int

Len returns the number of rows in the IndexedFrame or 0 if the IndexedFrame has no rows. If the IndexedFrame has series of different lengths, then the longest length series is returned.

func (*IndexedFrame[I]) Low

func (f *IndexedFrame[I]) Low(i int) float64

Low returns the low price of the candle at index i. i is an EasyIndex. If i is out of bounds, 0 is returned. This is the equivalent to calling Float("Low", i).

func (*IndexedFrame[I]) LowIndex

func (f *IndexedFrame[I]) LowIndex(index I) float64

func (*IndexedFrame[I]) Lows

func (f *IndexedFrame[I]) Lows() *IndexedSeries[I]

Lows returns a FloatSeries of all the low prices in the IndexedFrame. This is equivalent to calling Series("Low").

func (*IndexedFrame[I]) Names

func (f *IndexedFrame[I]) Names() []string

Names returns a slice of the names of the series in the IndexedFrame.

func (*IndexedFrame[I]) Open

func (f *IndexedFrame[I]) Open(i int) float64

Open returns the open price of the candle at index i. i is an EasyIndex. If i is out of bounds, 0 is returned. This is the equivalent to calling Float("Open", i).

func (*IndexedFrame[I]) OpenIndex

func (f *IndexedFrame[I]) OpenIndex(index I) float64

func (*IndexedFrame[I]) Opens

func (f *IndexedFrame[I]) Opens() *IndexedSeries[I]

Opens returns a FloatSeries of all the open prices in the IndexedFrame. This is equivalent to calling Series("Open").

func (*IndexedFrame[I]) PushCandle

func (f *IndexedFrame[I]) PushCandle(date I, open, high, low, close float64, volume int64) error

PushCandle pushes a candlestick to the IndexedFrame. If the IndexedFrame does not contain the series "Date", "Open", "High", "Low", "Close", and "Volume", an error is returned.

func (*IndexedFrame[I]) PushSeries

func (f *IndexedFrame[I]) PushSeries(series ...*IndexedSeries[I]) error

PushSeries adds the given series to the IndexedFrame. If the IndexedFrame already contains a series with the same name, an error is returned.

func (*IndexedFrame[I]) RemoveSeries

func (f *IndexedFrame[I]) RemoveSeries(names ...string)

RemoveSeries removes the given series from the IndexedFrame. If the IndexedFrame does not contain a series with a given name, nothing happens.

func (*IndexedFrame[I]) Select

func (f *IndexedFrame[I]) Select(names ...string) *IndexedFrame[I]

Select returns a new IndexedFrame with the selected Series. The series are not copied so the returned IndexedFrame will be a reference to the current IndexedFrame. If a series name is not found, it is ignored.

func (*IndexedFrame[I]) Series

func (f *IndexedFrame[I]) Series(name string) *IndexedSeries[I]

Series returns a Series of the column with the given name. If the column does not exist, nil is returned.

func (*IndexedFrame[I]) Shift

func (f *IndexedFrame[I]) Shift(periods int, nilValue any) *IndexedFrame[I]

func (*IndexedFrame[I]) ShiftIndex

func (f *IndexedFrame[I]) ShiftIndex(periods int, step func(prev I, amt int) I) *IndexedFrame[I]

func (*IndexedFrame[I]) Str

func (f *IndexedFrame[I]) Str(column string, i int) string

Str returns the string value of the column at index i. i is an EasyIndex. If i is out of bounds or the value was not a string, then the empty string "" is returned.

func (*IndexedFrame[I]) StrIndex

func (f *IndexedFrame[I]) StrIndex(column string, index I) string

func (*IndexedFrame[I]) String

func (f *IndexedFrame[I]) String() string

String returns a string representation of the IndexedFrame. If the IndexedFrame is nil, it will return the string "*autotrader.IndexedFrame[nil]". Otherwise, it will return a string like:

	*autotrader.IndexedFrame[2x6]
	   Date        Open  High  Low  Close  Volume
	1  2019-01-01  1     2     3    4      5
    2  2019-01-02  4     5     6    7      8

The order of the columns is not defined.

If the IndexedFrame has more than 20 rows, the output will include the first ten rows and the last ten rows.

func (*IndexedFrame[I]) Time

func (f *IndexedFrame[I]) Time(column string, i int) time.Time

Time returns the time.Time value of the column at index i. i is an EasyIndex. If i is out of bounds or the value was not a Time, then time.Time{} is returned. Use Time.IsZero() to check if the value was valid.

func (*IndexedFrame[I]) TimeIndex

func (f *IndexedFrame[I]) TimeIndex(column string, index I) time.Time

func (*IndexedFrame[I]) Value

func (f *IndexedFrame[I]) Value(column string, i int) any

Value returns the value of the column at index i. i is an EasyIndex. If i is out of bounds, nil is returned.

func (*IndexedFrame[I]) ValueIndex

func (f *IndexedFrame[I]) ValueIndex(column string, index I) any

func (*IndexedFrame[I]) Volume

func (f *IndexedFrame[I]) Volume(i int) int

Volume returns the volume of the candle at index i. i is an EasyIndex. If i is out of bounds, 0 is returned. This is the equivalent to calling Float("Volume", i).

func (*IndexedFrame[I]) VolumeIndex

func (f *IndexedFrame[I]) VolumeIndex(index I) int

func (*IndexedFrame[I]) Volumes

func (f *IndexedFrame[I]) Volumes() *IndexedSeries[I]

Volumes returns a Series of all the volumes in the IndexedFrame. This is equivalent to calling Series("Volume").

type IndexedRollingSeries

type IndexedRollingSeries[I Index] struct {
	// contains filtered or unexported fields
}

func NewIndexedRollingSeries

func NewIndexedRollingSeries[I Index](series *IndexedSeries[I], period int) *IndexedRollingSeries[I]

func (*IndexedRollingSeries[I]) Average

func (s *IndexedRollingSeries[I]) Average() *IndexedSeries[I]

func (*IndexedRollingSeries[I]) EMA

func (s *IndexedRollingSeries[I]) EMA() *IndexedSeries[I]

func (*IndexedRollingSeries[I]) Max

func (s *IndexedRollingSeries[I]) Max() *IndexedSeries[I]

func (*IndexedRollingSeries[I]) Mean

func (s *IndexedRollingSeries[I]) Mean() *IndexedSeries[I]

func (*IndexedRollingSeries[I]) Median

func (s *IndexedRollingSeries[I]) Median() *IndexedSeries[I]

func (*IndexedRollingSeries[I]) Min

func (s *IndexedRollingSeries[I]) Min() *IndexedSeries[I]

func (*IndexedRollingSeries[I]) Period

func (s *IndexedRollingSeries[I]) Period(row int) []any

func (*IndexedRollingSeries[I]) StdDev

func (s *IndexedRollingSeries[I]) StdDev() *IndexedSeries[I]

type IndexedSeries

type IndexedSeries[I Index] struct {
	*SignalManager
	// contains filtered or unexported fields
}

IndexedSeries is a Series with a custom index type.

func NewIndexedSeries

func NewIndexedSeries[I Index, V any](name string, vals map[I]V) *IndexedSeries[I]

NewIndexedSeries returns a new IndexedSeries with the given name and index type.

func (*IndexedSeries[I]) Add

func (s *IndexedSeries[I]) Add(other *IndexedSeries[I]) *IndexedSeries[I]

Add adds the values of the other series to the values of this series. The other series must have the same index type. The values are added by comparing their indexes. For example, adding two IndexedSeries that share no indexes will result in no change of values.

func (*IndexedSeries[I]) AddFloat

func (s *IndexedSeries[I]) AddFloat(num float64) *IndexedSeries[I]

func (*IndexedSeries[I]) Copy

func (s *IndexedSeries[I]) Copy() *IndexedSeries[I]

Copy returns a copy of this series.

func (*IndexedSeries[I]) CopyRange

func (s *IndexedSeries[I]) CopyRange(start, count int) *IndexedSeries[I]

CopyRange returns a copy of this series with the given range.

func (*IndexedSeries[I]) Div

func (s *IndexedSeries[I]) Div(other *IndexedSeries[I]) *IndexedSeries[I]

Div divides this series values with the other series values. The other series must have the same index type. The values are divided by comparing their indexes. For example, dividing two IndexedSeries that share no indexes will result in no change of values.

func (*IndexedSeries[I]) DivFloat

func (s *IndexedSeries[I]) DivFloat(num float64) *IndexedSeries[I]

func (*IndexedSeries[I]) Filter

func (s *IndexedSeries[I]) Filter(f func(i int, val any) bool) *IndexedSeries[I]

func (*IndexedSeries[I]) Float

func (s *IndexedSeries[I]) Float(i int) float64

func (*IndexedSeries[I]) FloatIndex

func (s *IndexedSeries[I]) FloatIndex(index I) float64

func (*IndexedSeries[I]) ForEach

func (s *IndexedSeries[I]) ForEach(f func(i int, val any)) *IndexedSeries[I]

func (*IndexedSeries[I]) Index

func (s *IndexedSeries[I]) Index(row int) *I

Index returns the index of the given row or nil if the row is out of bounds. row is an EasyIndex.

The performance of this operation is O(1).

func (*IndexedSeries[I]) Insert

func (s *IndexedSeries[I]) Insert(index I, val any) *IndexedSeries[I]

Insert adds a value to the series at the given index. If the index already exists, the value will be overwritten. The indexes are sorted using comparison operators.

func (*IndexedSeries[I]) Len

func (s *IndexedSeries[I]) Len() int

Len returns the number of rows in the series.

func (*IndexedSeries[I]) Map

func (s *IndexedSeries[I]) Map(f func(index I, row int, val any) any) *IndexedSeries[I]

func (*IndexedSeries[I]) MapReverse

func (s *IndexedSeries[I]) MapReverse(f func(index I, row int, val any) any) *IndexedSeries[I]

func (*IndexedSeries[I]) Mul

func (s *IndexedSeries[I]) Mul(other *IndexedSeries[I]) *IndexedSeries[I]

Mul multiplies this series values with the other series values. The other series must have the same index type. The values are multiplied by comparing their indexes. For example, multiplying two IndexedSeries that share no indexes will result in no change of values.

func (*IndexedSeries[I]) MulFloat

func (s *IndexedSeries[I]) MulFloat(num float64) *IndexedSeries[I]

func (*IndexedSeries[I]) Name

func (s *IndexedSeries[I]) Name() string

Name returns the name of the series.

func (*IndexedSeries[I]) Remove

func (s *IndexedSeries[I]) Remove(index I) any

Remove deletes the row at the given index and returns it.

func (*IndexedSeries[I]) RemoveRange

func (s *IndexedSeries[I]) RemoveRange(start, count int) *IndexedSeries[I]

RemoveRange deletes the rows in the given range and returns the series.

The operation is O(n) where n is the number of rows in the series.

func (*IndexedSeries[I]) Reverse

func (s *IndexedSeries[I]) Reverse() *IndexedSeries[I]

Reverse reverses the rows of the series.

func (*IndexedSeries[I]) Rolling

func (s *IndexedSeries[I]) Rolling(period int) *IndexedRollingSeries[I]

func (*IndexedSeries[I]) Row

func (s *IndexedSeries[I]) Row(index I) int

Row returns the row of the given index or -1 if the index does not exist.

The performance of this operation is O(1).

func (*IndexedSeries[I]) SetName

func (s *IndexedSeries[I]) SetName(name string) *IndexedSeries[I]

func (*IndexedSeries[I]) SetValue

func (s *IndexedSeries[I]) SetValue(row int, val any) *IndexedSeries[I]

func (*IndexedSeries[I]) SetValueIndex

func (s *IndexedSeries[I]) SetValueIndex(index I, val any) *IndexedSeries[I]

SetValueIndex is like SetValue but uses the index instead of the row.

func (*IndexedSeries[I]) Shift

func (s *IndexedSeries[I]) Shift(periods int, nilValue any) *IndexedSeries[I]

func (*IndexedSeries[I]) ShiftIndex

func (s *IndexedSeries[I]) ShiftIndex(periods int, step func(prev I, amt int) I) *IndexedSeries[I]

func (*IndexedSeries[I]) String

func (s *IndexedSeries[I]) String() string

func (*IndexedSeries[I]) Sub

func (s *IndexedSeries[I]) Sub(other *IndexedSeries[I]) *IndexedSeries[I]

Sub subtracts the other series values from this series values. The other series must have the same index type. The values are subtracted by comparing their indexes. For example, subtracting two IndexedSeries that share no indexes will result in no change of values.

func (*IndexedSeries[I]) SubFloat

func (s *IndexedSeries[I]) SubFloat(num float64) *IndexedSeries[I]

func (*IndexedSeries[I]) Value

func (s *IndexedSeries[I]) Value(i int) any

Value returns the value at the given row.

func (*IndexedSeries[I]) ValueIndex

func (s *IndexedSeries[I]) ValueIndex(index I) any

ValueIndex returns the value at the given index or nil if the index does not exist.

func (*IndexedSeries[I]) ValueRange

func (s *IndexedSeries[I]) ValueRange(start, count int) []any

ValueRange returns a copy of the values in the given range. start is an EasyIndex. count is the number of values to return. If count is -1, all values after start are returned. See Series.ValueRange() for more information.

func (*IndexedSeries[I]) Values

func (s *IndexedSeries[I]) Values() []any

Values returns a copy of the values in the series.

type Order

type Order interface {
	Cancel() error         // Cancel attempts to cancel the order and returns an error if it fails. If the error is nil, the order was canceled.
	Fulfilled() bool       // Fulfilled returns true if the order has been filled with the broker and a position is active.
	Id() string            // Id returns the unique identifier of the order by the broker.
	Leverage() float64     // Leverage returns the leverage of the order.
	Position() Position    // Position returns the position of the order. If the order has not been filled, nil is returned.
	Price() float64        // Price returns the price of the symbol at the time the order was placed.
	Symbol() string        // Symbol returns the symbol name of the order.
	TrailingStop() float64 // TrailingStop returns the trailing stop loss distance of the order.
	StopLoss() float64     // StopLoss returns the stop loss price of the order.
	TakeProfit() float64   // TakeProfit returns the take profit price of the order.
	Time() time.Time       // Time returns the time the order was placed.
	Type() OrderType       // Type returns the type of order.
	Units() float64        // Units returns the number of units purchased or sold by the order.
}

type OrderCloseType

type OrderCloseType string

type OrderType

type OrderType string
const (
	Market OrderType = "MARKET" // Market means to buy or sell at the current market price, which may not always be what you expect.
	Limit  OrderType = "LIMIT"  // Limit means to buy or sell at a specific price or better.
	Stop   OrderType = "STOP"   // Stop means to buy or sell when the price reaches a specific price or ASAP.
)

type Position

type Position interface {
	Close() error              // Close attempts to close the position and returns an error if it fails. If the error is nil, the position was closed.
	Closed() bool              // Closed returns true if the position has been closed with the broker.
	CloseType() OrderCloseType // CloseType returns the type of order used to close the position.
	ClosePrice() float64       // ClosePrice returns the price of the symbol at the time the position was closed. May be zero if the position is still open.
	EntryPrice() float64       // EntryPrice returns the price of the symbol at the time the position was opened.
	EntryValue() float64       // EntryValue returns the value of the position at the time it was opened.
	Id() string                // Id returns the unique identifier of the position by the broker.
	Leverage() float64         // Leverage returns the leverage of the position.
	PL() float64               // PL returns the profit or loss of the position.
	Symbol() string            // Symbol returns the symbol name of the position.
	TrailingStop() float64     // TrailingStop returns the trailing stop loss price of the position.
	StopLoss() float64         // StopLoss returns the stop loss price of the position.
	TakeProfit() float64       // TakeProfit returns the take profit price of the position.
	Time() time.Time           // Time returns the time the position was opened.
	Units() float64            // Units returns the number of units purchased or sold by the position.
	Value() float64            // Value returns the value of the position at the current price.
}

type RollingSeries

type RollingSeries struct {
	// contains filtered or unexported fields
}

func NewRollingSeries

func NewRollingSeries(series *Series, period int) *RollingSeries

func (*RollingSeries) Average

func (s *RollingSeries) Average() *Series

Average is an alias for Mean.

func (*RollingSeries) EMA

func (s *RollingSeries) EMA() *Series

EMA returns the exponential moving average of the period as a float64 or 0 if the period requested is empty.

Will work with all signed int and float types. Ignores all other values.

func (*RollingSeries) Max

func (s *RollingSeries) Max() *Series

Max returns the underlying series with each value mapped to the maximum of its period as a float64 or 0 if the requested period is empty.

Will work with all signed int and float types. Ignores all other values.

func (*RollingSeries) Mean

func (s *RollingSeries) Mean() *Series

Mean returns the mean of the rolling period as a float64 or 0 if the period requested is empty.

Will work with all signed int and float types. Ignores all other values.

func (*RollingSeries) Median

func (s *RollingSeries) Median() *Series

Median returns the median of the period as a float64 or 0 if the period requested is empty.

Will work with float64 and int. Ignores all other values.

func (*RollingSeries) Min

func (s *RollingSeries) Min() *Series

Min returns an AppliedSeries that returns the minimum value of the rolling period as a float64 or 0 if the requested period is empty.

Will work with all signed int and float types. Ignores all other values.

func (*RollingSeries) Period

func (s *RollingSeries) Period(row int) []any

Period returns a slice of 'any' values with a length up to the period of the RollingSeries. The last item in the slice is the item at row. If row is out of bounds, nil is returned.

func (*RollingSeries) StdDev

func (s *RollingSeries) StdDev() *Series

StdDev returns the standard deviation of the period as a float64 or 0 if the period requested is empty.

type Series

type Series struct {
	SignalManager
	// contains filtered or unexported fields
}

Series is a slice of any values with a name. It is used to represent a column in a DataFrame. The type contains various functions to perform mutating operations on the data. All mutating operations return a pointer to the Series so that they can be chained together. To create a copy of a Series before applying operations, use the Copy() or CopyRange() functions.

Signals:

  • LengthChanged(int) - when the data is appended or an item is removed.
  • NameChanged(string) - when the name is changed.
  • ValueChanged(int, any) - when a value is changed.

func NewSeries

func NewSeries(name string, vals ...any) *Series

func (*Series) Add

func (s *Series) Add(other *Series) *Series

func (*Series) Copy

func (s *Series) Copy() *Series

Copy is equivalent to CopyRange(0, -1).

func (*Series) CopyRange

func (s *Series) CopyRange(start, count int) *Series

CopyRange returns a new Series with a copy of the original data and name. start is an EasyIndex and count is the number of items to copy from start onward. If count is negative then all items from start to the end of the series are copied. If there are not enough items to copy then the maximum amount is returned. If there are no items to copy then an empty DataSeries is returned.

Examples:

CopyRange(0, 10) - copy the first 10 items
CopyRange(-1, 1) - copy the last item
CopyRange(-10, -1) - copy the last 10 items

All signals are disconnected from the copy.

func (*Series) Div

func (s *Series) Div(other *Series) *Series

func (*Series) Filter

func (s *Series) Filter(f func(i int, val any) bool) *Series

func (*Series) Float

func (s *Series) Float(i int) float64

Float returns the value at index i as a float64. If the value is not a float64 then 0 is returned.

func (*Series) ForEach

func (s *Series) ForEach(f func(i int, val any)) *Series

func (*Series) ISetName

func (s *Series) ISetName(name string)

func (*Series) Insert

func (s *Series) Insert(i int, value any) *Series

func (*Series) Int

func (s *Series) Int(i int) int

Int returns the value at index i as an int64. If the value is not an int64 then 0 is returned.

func (*Series) Len

func (s *Series) Len() int

Len returns the number of rows in the Series.

func (*Series) Map

func (s *Series) Map(f func(i int, val any) any) *Series

func (*Series) MapReverse

func (s *Series) MapReverse(f func(i int, val any) any) *Series

MapReverse is equivalent to Map except that it iterates over the series in reverse order. This is useful when you want to retrieve values before i that are not modified by the map function, for example when calculating a moving average.

func (*Series) MaxFloat

func (s *Series) MaxFloat() float64

func (*Series) MaxInt

func (s *Series) MaxInt() int

func (*Series) MinFloat

func (s *Series) MinFloat() float64

func (*Series) MinInt

func (s *Series) MinInt() int

func (*Series) Mul

func (s *Series) Mul(other *Series) *Series

func (*Series) Name

func (s *Series) Name() string

Name returns the name of the Series.

func (*Series) Pop

func (s *Series) Pop() any

Pop will remove the last value from the Series and emit a LengthChanged signal.

func (*Series) Push

func (s *Series) Push(value any) *Series

Push will append a value to the end of the Series and emit a LengthChanged signal.

func (*Series) Range

func (s *Series) Range(start, count int) (begin, end int)

Range takes an EasyIndex start and a number of items to select with count, and returns a range from begin to end, exclusive. If count is negative then the range spans to the end of the series. begin will always be between 0 and len-1. end will always be between start and len. If the range is empty then begin and end will be the same value.

func (*Series) Remove

func (s *Series) Remove(i int) any

Remove removes and returns the value at index i and emits a LengthChanged signal. If i is out of bounds then nil is returned.

func (*Series) RemoveRange

func (s *Series) RemoveRange(start, count int) *Series

RemoveRange removes count items starting at index start and emits a LengthChanged signal.

func (*Series) Reverse

func (s *Series) Reverse() *Series

Reverse will reverse the order of the values in the Series and emit a ValueChanged signal for each value.

func (*Series) Rolling

func (s *Series) Rolling(period int) *RollingSeries

func (*Series) SetName

func (s *Series) SetName(name string) *Series

SetName sets the name of the series to name and emits a NameChanged signal.

func (*Series) SetValue

func (s *Series) SetValue(i int, val any) *Series

func (*Series) Shift

func (s *Series) Shift(periods int, nilVal any) *Series

func (*Series) Str

func (s *Series) Str(i int) string

Str returns the value at index i as a string. If the value is not a string then "" is returned.

func (*Series) Sub

func (s *Series) Sub(other *Series) *Series

func (*Series) Time

func (s *Series) Time(i int) time.Time

Time returns the value at index i as a time.Time. If the value is not a time.Time then time.Time{} is returned. Use Time.IsZero() to check if the value returned was not a Time.

func (*Series) Value

func (s *Series) Value(i int) any

func (*Series) ValueRange

func (s *Series) ValueRange(start, count int) []any

ValueRange returns a copy of values from start to start+count. If count is negative then all items from start to the end of the series are returned. If there are not enough items to return then the maximum amount is returned. If there are no items to return then an empty slice is returned.

func (*Series) Values

func (s *Series) Values() []any

Values returns a copy of all values. If there are no values, an empty slice is returned.

Same as:

ValueRange(0, -1)

type SignalHandler

type SignalHandler struct {
	Identity any          // Identity is used to identify functions implemented on the same type. It is typically a pointer to an object that owns the callback function, but it can be a string or any other type.
	Callback func(...any) // Callback is the function that is called when the signal is emitted.
	Bindings []any        // Bindings are arguments that are passed to the callback function when the signal is emitted. These are typically used to pass context.
}

SignalHandler wraps a signal handler.

type SignalManager

type SignalManager struct {
	// contains filtered or unexported fields
}

SignalManager is a struct that implements the Signaler interface. Embed this into your struct to have signals entirely for free. Emitting a signal will call all handlers connected to the signal, but if no handlers are connected then it is a no-op. This means signals are very cheap and only come at a cost when they're actually used.

func (*SignalManager) SignalConnect

func (s *SignalManager) SignalConnect(signal string, identity any, callback func(...any), bindings ...any) error

SignalConnect connects a callback function to the signal. The callback function will be called when the signal is emitted. The identity is used to identify functions implemented on the same type. It is typically a pointer to an object that owns the callback function, but it can be a string or any other type. Bindings are arguments that are passed to the callback function when the signal is emitted. These are typically used to pass context.

func (*SignalManager) SignalConnected

func (s *SignalManager) SignalConnected(signal string, identity any, callback func(...any)) bool

SignalConnected returns true if the callback function under the identity is connected to the signal.

func (*SignalManager) SignalConnections

func (s *SignalManager) SignalConnections(signal string) []SignalHandler

SignalConnections returns a slice of handlers connected to the signal.

func (*SignalManager) SignalDisconnect

func (s *SignalManager) SignalDisconnect(signal string, identity any, callback func(...any))

SignalDisconnect removes the equivalent callback function under the identity from the signal.

func (*SignalManager) SignalEmit

func (s *SignalManager) SignalEmit(signal string, data ...any)

SignalEmit calls all handlers connected to the signal with the data. If no handlers are connected then it is a no-op.

type Signaler

type Signaler interface {
	SignalConnect(signal string, identity any, handler func(...any), bindings ...any) error // SignalConnect connects the handler to the signal under identity.
	SignalConnected(signal string, identity any, handler func(...any)) bool                 // SignalConnected returns true if the handler under the identity is connected to the signal.
	SignalConnections(signal string) []SignalHandler                                        // SignalConnections returns a slice of handlers connected to the signal.
	SignalDisconnect(signal string, identity any, handler func(...any))                     // SignalDisconnect removes the handler under identity from the signal.
	SignalEmit(signal string, data ...any)                                                  // SignalEmit emits the signal with the data.
}

Signaler is an interface for objects that can emit signals which fire event handlers. This is used to implement event-driven programming. Embed a pointer to a SignalManager in your struct to have signals entirely for free.

Example:

type MyStruct struct {
	*SignalManager // Now MyStruct has SignalConnect, SignalEmit, etc.
}

When your type emits signals, they should be listed somewhere in the documentation. For example:

// Signals:
//  - MySignal() - Emitted when...
//  - ThingChanged(newThing *Thing) - Emitted when a thing changes.
type MyStruct struct { ... }

type Strategy

type Strategy interface {
	Init(t *Trader)
	Next(t *Trader)
}

type TestBroker

type TestBroker struct {
	SignalManager
	DataBroker Broker
	Data       *IndexedFrame[UnixTime]
	Cash       float64
	Leverage   float64
	Spread     float64 // Number of pips to add to the price when buying and subtract when selling. (Forex)
	Slippage   float64 // A percentage of the price to add when buying and subtract when selling.
	// contains filtered or unexported fields
}

TestBroker is a broker that can be used for testing. It implements the Broker interface and fulfills orders

Signals:

  • Tick(nil) - Called when the broker ticks.
  • OrderPlaced(Order) - Called when an order is placed.
  • OrderFilled(Order) - Called when an order is filled.
  • OrderCanceled(Order) - Called when an order is canceled.
  • PositionClosed(Position) - Called when a position is closed.
  • PositionModified(Position) - Called when a position changes.

func NewTestBroker

func NewTestBroker(dataBroker Broker, data *IndexedFrame[UnixTime], cash, leverage, spread float64, startCandles int) *TestBroker

func (*TestBroker) Advance

func (b *TestBroker) Advance()

Advance advances the test broker to the next candle in the input data. This should be done at the end of the strategy loop. This will also call Tick() to update orders and positions.

func (*TestBroker) Ask

func (b *TestBroker) Ask(_ string) float64

Ask returns the price a buyer pays for the current candle.

func (*TestBroker) Bid

func (b *TestBroker) Bid(_ string) float64

Bid returns the price a seller receives for the current candle.

func (*TestBroker) CandleIndex

func (b *TestBroker) CandleIndex() int

CandleIndex returns the index of the current candle.

func (*TestBroker) Candles

func (b *TestBroker) Candles(symbol string, frequency string, count int) (*IndexedFrame[UnixTime], error)

Candles returns the last count candles for the given symbol and frequency. If count is greater than the number of candles, then a dataframe with zero rows is returned.

If the TestBroker has a data broker set, then it will use that to get candles. Otherwise, it will return the candles from the data that was set. The first call to Candles will fetch candles from the data broker if it is set, so it is recommended to set the data broker before the first call to Candles and to call Candles the first time with the number of candles you want to fetch.

func (*TestBroker) NAV

func (b *TestBroker) NAV() float64

func (*TestBroker) OpenOrders

func (b *TestBroker) OpenOrders() []Order

func (*TestBroker) OpenPositions

func (b *TestBroker) OpenPositions() []Position

func (*TestBroker) Order

func (b *TestBroker) Order(orderType OrderType, symbol string, units, price, stopLoss, takeProfit float64) (Order, error)

func (*TestBroker) Orders

func (b *TestBroker) Orders() []Order

func (*TestBroker) PL

func (b *TestBroker) PL() float64

func (*TestBroker) Positions

func (b *TestBroker) Positions() []Position

func (*TestBroker) Price

func (b *TestBroker) Price(symbol string, wantToBuy bool) float64

Price returns the ask price if wantToBuy is true and the bid price if wantToBuy is false.

func (*TestBroker) SpreadCollected

func (b *TestBroker) SpreadCollected() float64

SpreadCollected returns the total amount of spread collected from trades, in USD.

func (*TestBroker) Tick

func (b *TestBroker) Tick()

type TestOrder

type TestOrder struct {
	// contains filtered or unexported fields
}

func (*TestOrder) Cancel

func (o *TestOrder) Cancel() error

func (*TestOrder) Fulfilled

func (o *TestOrder) Fulfilled() bool

func (*TestOrder) Id

func (o *TestOrder) Id() string

func (*TestOrder) Leverage

func (o *TestOrder) Leverage() float64

func (*TestOrder) Position

func (o *TestOrder) Position() Position

func (*TestOrder) Price

func (o *TestOrder) Price() float64

func (*TestOrder) StopLoss

func (o *TestOrder) StopLoss() float64

func (*TestOrder) Symbol

func (o *TestOrder) Symbol() string

func (*TestOrder) TakeProfit

func (o *TestOrder) TakeProfit() float64

func (*TestOrder) Time

func (o *TestOrder) Time() time.Time

func (*TestOrder) TrailingStop

func (o *TestOrder) TrailingStop() float64

func (*TestOrder) Type

func (o *TestOrder) Type() OrderType

func (*TestOrder) Units

func (o *TestOrder) Units() float64

type TestPosition

type TestPosition struct {
	// contains filtered or unexported fields
}

func (*TestPosition) Close

func (p *TestPosition) Close() error

func (*TestPosition) ClosePrice

func (p *TestPosition) ClosePrice() float64

func (*TestPosition) CloseType

func (p *TestPosition) CloseType() OrderCloseType

func (*TestPosition) Closed

func (p *TestPosition) Closed() bool

func (*TestPosition) EntryPrice

func (p *TestPosition) EntryPrice() float64

func (*TestPosition) EntryValue

func (p *TestPosition) EntryValue() float64

func (*TestPosition) Id

func (p *TestPosition) Id() string

func (*TestPosition) Leverage

func (p *TestPosition) Leverage() float64

func (*TestPosition) PL

func (p *TestPosition) PL() float64

func (*TestPosition) StopLoss

func (p *TestPosition) StopLoss() float64

func (*TestPosition) Symbol

func (p *TestPosition) Symbol() string

func (*TestPosition) TakeProfit

func (p *TestPosition) TakeProfit() float64

func (*TestPosition) Time

func (p *TestPosition) Time() time.Time

func (*TestPosition) TrailingStop

func (p *TestPosition) TrailingStop() float64

func (*TestPosition) Units

func (p *TestPosition) Units() float64

func (*TestPosition) Value

func (p *TestPosition) Value() float64

type TradeStat

type TradeStat struct {
	Price float64 // Price is the price at which the trade was executed. If Exit is true, this is the exit price. Otherwise, this is the entry price.
	Units float64 // Units is the signed number of units bought or sold.
	Exit  bool    // Exit is true if the trade was to exit a previous position.
}

type Trader

type Trader struct {
	Broker        Broker
	Strategy      Strategy
	Symbol        string
	Frequency     string
	CandlesToKeep int
	Log           *log.Logger
	EOF           bool
	// contains filtered or unexported fields
}

Trader acts as the primary interface to the broker and strategy. To the strategy, it provides all the information about the current state of the market and the portfolio. To the broker, it provides the orders to be executed and requests for the current state of the portfolio.

func NewTrader

func NewTrader(config TraderConfig) *Trader

NewTrader initializes a new Trader which can be used for live trading or backtesting.

func (*Trader) Buy

func (t *Trader) Buy(units, stopLoss, takeProfit float64) (Order, error)

Buy creates a buy market order. Units must be greater than zero or ErrInvalidUnits is returned.

func (*Trader) CloseOrdersAndPositions

func (t *Trader) CloseOrdersAndPositions()

func (*Trader) Data

func (t *Trader) Data() *IndexedFrame[UnixTime]

func (*Trader) Init

func (t *Trader) Init()

func (*Trader) IsLong

func (t *Trader) IsLong() bool

func (*Trader) IsShort

func (t *Trader) IsShort() bool

func (*Trader) Order

func (t *Trader) Order(orderType OrderType, units, price, stopLoss, takeProfit float64) (Order, error)

func (*Trader) Run

func (t *Trader) Run()

Run starts the trader. This is a blocking call.

func (*Trader) Sell

func (t *Trader) Sell(units, stopLoss, takeProfit float64) (Order, error)

Sell creates a sell market order. Units must be greater than zero or ErrInvalidUnits is returned.

func (*Trader) Stats

func (t *Trader) Stats() *TraderStats

func (*Trader) Tick

func (t *Trader) Tick()

Tick updates the current state of the market and runs the strategy.

type TraderConfig

type TraderConfig struct {
	Broker        Broker
	Strategy      Strategy
	Symbol        string
	Frequency     string
	CandlesToKeep int
}

type TraderStats

type TraderStats struct {
	Dated *Frame
	// contains filtered or unexported fields
}

Financial performance reporting and statistics.

type UnixTime

type UnixTime int64

UnixTime is a wrapper over the number of milliseconds since January 1, 1970, AKA Unix time.

func (UnixTime) String

func (t UnixTime) String() string

String returns the string representation of the UnixTime.

func (UnixTime) Time

func (t UnixTime) Time() time.Time

Time converts the UnixTime to a time.Time.

Directories

Path Synopsis
oanda module

Jump to

Keyboard shortcuts

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