backtest

package
v0.0.0-...-cb4139d Latest Latest
Warning

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

Go to latest
Published: Jul 15, 2023 License: AGPL-3.0 Imports: 29 Imported by: 0

Documentation

Overview

The backtest process

The backtest engine loads the klines from the database into a kline-channel, there are multiple matching engine that matches the order sent from the strategy.

for each kline, the backtest engine:

1) load the kline, run matching logics to send out order update and trades to the user data stream. 2) once the matching process for the kline is done, the kline will be pushed to the market data stream. 3) go to 1 and load the next kline.

There are 2 ways that a strategy could work with backtest engine:

  1. the strategy receives kline from the market data stream, and then it submits the order by the given market data to the backtest engine. backtest engine receives the order and then pushes the trade and order updates to the user data stream.

    the strategy receives the trade and update its position.

  2. the strategy places the orders when it starts. (like grid) the strategy then receives the order updates and then submit a new order by its order update message.

We need to ensure that:

  1. if the strategy submits the order from the market data stream, since it's a separate goroutine, the strategy should block the backtest engine to process the trades before the next kline is published.

Index

Constants

View Source
const DateFormat = "2006-01-02T15:04"
View Source
const FeeToken = "FEE"

FeeToken is used to simulate the exchange platform fee token This is to ease the back-testing environment for closing positions.

View Source
const SessionTimeFormat = "2006-01-02T15_04"

Variables

View Source
var ErrNegativeQuantity = errors.New("order quantity can not be negative")
View Source
var ErrUnimplemented = errors.New("unimplemented method")
View Source
var ErrZeroQuantity = errors.New("order quantity can not be zero")
View Source
var FS = &fs{}

Functions

func AddReportIndexRun

func AddReportIndexRun(outputDirectory string, run Run) error

func CollectSubscriptionIntervals

func CollectSubscriptionIntervals(environ *bbgo.Environment) (allKLineIntervals map[types.Interval]struct{}, requiredInterval types.Interval, backTestIntervals []types.Interval)

func FormatSessionName

func FormatSessionName(sessions []string, symbols []string, startTime, endTime time.Time) string

FormatSessionName returns the back-test session name

func InQuoteAsset

func InQuoteAsset(balances types.BalanceMap, market types.Market, price fixedpoint.Value) fixedpoint.Value

InQuoteAsset converts all balances in quote asset

func WriteReportIndex

func WriteReportIndex(outputDirectory string, reportIndex *ReportIndex) error

Types

type Exchange

type Exchange struct {
	MarketDataStream types.StandardStreamEmitter

	Src *ExchangeDataSource
	// contains filtered or unexported fields
}

func NewExchange

func NewExchange(sourceName types.ExchangeName, sourceExchange types.Exchange, srv *service.BacktestService, config *bbgo.Backtest) (*Exchange, error)

func (*Exchange) BindUserData

func (e *Exchange) BindUserData(userDataStream types.StandardStreamEmitter)

func (*Exchange) CancelOrders

func (e *Exchange) CancelOrders(ctx context.Context, orders ...types.Order) error

func (*Exchange) CloseMarketData

func (e *Exchange) CloseMarketData() error

func (*Exchange) ConsumeKLine

func (e *Exchange) ConsumeKLine(k types.KLine, requiredInterval types.Interval)

func (*Exchange) Name

func (e *Exchange) Name() types.ExchangeName

func (*Exchange) NewStream

func (e *Exchange) NewStream() types.Stream

func (*Exchange) PlatformFeeCurrency

func (e *Exchange) PlatformFeeCurrency() string

func (*Exchange) QueryAccount

func (e *Exchange) QueryAccount(ctx context.Context) (*types.Account, error)

func (*Exchange) QueryAccountBalances

func (e *Exchange) QueryAccountBalances(ctx context.Context) (types.BalanceMap, error)

func (*Exchange) QueryClosedOrders

func (e *Exchange) QueryClosedOrders(ctx context.Context, symbol string, since, until time.Time, lastOrderID uint64) (orders []types.Order, err error)

func (*Exchange) QueryDepositHistory

func (e *Exchange) QueryDepositHistory(ctx context.Context, asset string, since, until time.Time) (allDeposits []types.Deposit, err error)

func (*Exchange) QueryKLines

func (e *Exchange) QueryKLines(ctx context.Context, symbol string, interval types.Interval, options types.KLineQueryOptions) ([]types.KLine, error)

func (*Exchange) QueryMarkets

func (e *Exchange) QueryMarkets(ctx context.Context) (types.MarketMap, error)

func (*Exchange) QueryOpenOrders

func (e *Exchange) QueryOpenOrders(ctx context.Context, symbol string) (orders []types.Order, err error)

func (*Exchange) QueryOrder

func (e *Exchange) QueryOrder(ctx context.Context, q types.OrderQuery) (*types.Order, error)

func (*Exchange) QueryTicker

func (e *Exchange) QueryTicker(ctx context.Context, symbol string) (*types.Ticker, error)

func (*Exchange) QueryTickers

func (e *Exchange) QueryTickers(ctx context.Context, symbol ...string) (map[string]types.Ticker, error)

func (*Exchange) QueryTrades

func (e *Exchange) QueryTrades(ctx context.Context, symbol string, options *types.TradeQueryOptions) ([]types.Trade, error)

func (*Exchange) QueryWithdrawHistory

func (e *Exchange) QueryWithdrawHistory(ctx context.Context, asset string, since, until time.Time) (allWithdraws []types.Withdraw, err error)

func (*Exchange) SubmitOrder

func (e *Exchange) SubmitOrder(ctx context.Context, order types.SubmitOrder) (createdOrder *types.Order, err error)

func (*Exchange) SubscribeMarketData

func (e *Exchange) SubscribeMarketData(startTime, endTime time.Time, requiredInterval types.Interval, extraIntervals ...types.Interval) (chan types.KLine, error)

type ExchangeDataSource

type ExchangeDataSource struct {
	C         chan types.KLine
	Exchange  *Exchange
	Session   *bbgo.ExchangeSession
	Callbacks []func(types.KLine, *ExchangeDataSource)
}

func InitializeExchangeSources

func InitializeExchangeSources(sessions map[string]*bbgo.ExchangeSession, startTime, endTime time.Time, requiredInterval types.Interval, extraIntervals ...types.Interval) (exchangeSources []*ExchangeDataSource, err error)

type FeeModeFunction

type FeeModeFunction func(order *types.Order, market *types.Market, feeRate fixedpoint.Value) (fee fixedpoint.Value, feeCurrency string)

type Instance

type Instance interface {
	ID() string
	InstanceID() string
}

type InstancePropertyIndex

type InstancePropertyIndex struct {
	ID         string
	InstanceID string
	Property   string
}

type KLineDumper

type KLineDumper struct {
	OutputDirectory string
	// contains filtered or unexported fields
}

KLineDumper dumps the received kline data into a folder for the backtest report to load the charts.

func NewKLineDumper

func NewKLineDumper(outputDirectory string) *KLineDumper

func (*KLineDumper) Close

func (d *KLineDumper) Close() error

func (*KLineDumper) Filenames

func (d *KLineDumper) Filenames() map[symbolInterval]string

func (*KLineDumper) Record

func (d *KLineDumper) Record(k types.KLine) error

type ManifestEntry

type ManifestEntry struct {
	Type             string `json:"type"`
	Filename         string `json:"filename"`
	StrategyID       string `json:"strategyID"`
	StrategyInstance string `json:"strategyInstance"`
	StrategyProperty string `json:"strategyProperty"`
}

type Manifests

type Manifests map[InstancePropertyIndex]string

func (Manifests) MarshalJSON

func (m Manifests) MarshalJSON() ([]byte, error)

func (*Manifests) UnmarshalJSON

func (m *Manifests) UnmarshalJSON(j []byte) error

type PriceOrder

type PriceOrder struct {
	Price fixedpoint.Value
	Order types.Order
}

type PriceOrderSlice

type PriceOrderSlice []PriceOrder

func (PriceOrderSlice) Find

func (slice PriceOrderSlice) Find(price fixedpoint.Value, descending bool) (pv PriceOrder, idx int)

FindPriceVolumePair finds the pair by the given price, this function is a read-only operation, so we use the value receiver to avoid copy value from the pointer If the price is not found, it will return the index where the price can be inserted at. true for descending (bid orders), false for ascending (ask orders)

func (PriceOrderSlice) First

func (slice PriceOrderSlice) First() (PriceOrder, bool)

func (PriceOrderSlice) InsertAt

func (slice PriceOrderSlice) InsertAt(idx int, po PriceOrder) PriceOrderSlice

func (PriceOrderSlice) Len

func (slice PriceOrderSlice) Len() int

func (PriceOrderSlice) Less

func (slice PriceOrderSlice) Less(i, j int) bool

func (PriceOrderSlice) Remove

func (slice PriceOrderSlice) Remove(price fixedpoint.Value, descending bool) PriceOrderSlice

func (PriceOrderSlice) Swap

func (slice PriceOrderSlice) Swap(i, j int)

func (PriceOrderSlice) Upsert

func (slice PriceOrderSlice) Upsert(po PriceOrder, descending bool) PriceOrderSlice

type ReportIndex

type ReportIndex struct {
	Runs []Run `json:"runs,omitempty"`
}

func LoadReportIndex

func LoadReportIndex(outputDirectory string) (*ReportIndex, error)

type Run

type Run struct {
	ID     string       `json:"id"`
	Config *bbgo.Config `json:"config"`
	Time   time.Time    `json:"time"`
}

type SessionSymbolReport

type SessionSymbolReport struct {
	Exchange        types.ExchangeName        `json:"exchange"`
	Symbol          string                    `json:"symbol,omitempty"`
	Intervals       []types.Interval          `json:"intervals,omitempty"`
	Subscriptions   []types.Subscription      `json:"subscriptions"`
	Market          types.Market              `json:"market"`
	LastPrice       fixedpoint.Value          `json:"lastPrice,omitempty"`
	StartPrice      fixedpoint.Value          `json:"startPrice,omitempty"`
	PnL             *pnl.AverageCostPnLReport `json:"pnl,omitempty"`
	InitialBalances types.BalanceMap          `json:"initialBalances,omitempty"`
	FinalBalances   types.BalanceMap          `json:"finalBalances,omitempty"`
	Manifests       Manifests                 `json:"manifests,omitempty"`
	Sharpe          fixedpoint.Value          `json:"sharpeRatio"`
	Sortino         fixedpoint.Value          `json:"sortinoRatio"`
	ProfitFactor    fixedpoint.Value          `json:"profitFactor"`
	WinningRatio    fixedpoint.Value          `json:"winningRatio"`
}

SessionSymbolReport is the report per exchange session trades are merged, collected and re-calculated

func (*SessionSymbolReport) FinalEquityValue

func (r *SessionSymbolReport) FinalEquityValue() fixedpoint.Value

func (*SessionSymbolReport) InitialEquityValue

func (r *SessionSymbolReport) InitialEquityValue() fixedpoint.Value

func (*SessionSymbolReport) Print

func (r *SessionSymbolReport) Print(wantBaseAssetBaseline bool)

type SimplePriceMatching

type SimplePriceMatching struct {
	Symbol string
	Market types.Market
	// contains filtered or unexported fields
}

SimplePriceMatching implements a simple kline data driven matching engine for backtest

func (*SimplePriceMatching) CancelOrder

func (m *SimplePriceMatching) CancelOrder(o types.Order) (types.Order, error)

func (*SimplePriceMatching) EmitBalanceUpdate

func (m *SimplePriceMatching) EmitBalanceUpdate(balances types.BalanceMap)

func (*SimplePriceMatching) EmitOrderUpdate

func (m *SimplePriceMatching) EmitOrderUpdate(order types.Order)

func (*SimplePriceMatching) EmitTradeUpdate

func (m *SimplePriceMatching) EmitTradeUpdate(trade types.Trade)

func (*SimplePriceMatching) OnBalanceUpdate

func (m *SimplePriceMatching) OnBalanceUpdate(cb func(balances types.BalanceMap))

func (*SimplePriceMatching) OnOrderUpdate

func (m *SimplePriceMatching) OnOrderUpdate(cb func(order types.Order))

func (*SimplePriceMatching) OnTradeUpdate

func (m *SimplePriceMatching) OnTradeUpdate(cb func(trade types.Trade))

func (*SimplePriceMatching) PlaceOrder

PlaceOrder returns the created order object, executed trade (if any) and error

type StateRecorder

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

func NewStateRecorder

func NewStateRecorder(outputDir string) *StateRecorder

func (*StateRecorder) Close

func (r *StateRecorder) Close() error

func (*StateRecorder) Manifests

func (r *StateRecorder) Manifests() Manifests

func (*StateRecorder) Scan

func (r *StateRecorder) Scan(instance Instance) error

func (*StateRecorder) Snapshot

func (r *StateRecorder) Snapshot() (int, error)

type SummaryReport

type SummaryReport struct {
	StartTime            time.Time        `json:"startTime"`
	EndTime              time.Time        `json:"endTime"`
	Sessions             []string         `json:"sessions"`
	Symbols              []string         `json:"symbols"`
	Intervals            []types.Interval `json:"intervals"`
	InitialTotalBalances types.BalanceMap `json:"initialTotalBalances"`
	FinalTotalBalances   types.BalanceMap `json:"finalTotalBalances"`

	InitialEquityValue fixedpoint.Value `json:"initialEquityValue"`
	FinalEquityValue   fixedpoint.Value `json:"finalEquityValue"`

	// TotalProfit is the profit aggregated from the symbol reports
	TotalProfit           fixedpoint.Value `json:"totalProfit,omitempty"`
	TotalUnrealizedProfit fixedpoint.Value `json:"totalUnrealizedProfit,omitempty"`

	TotalGrossProfit fixedpoint.Value `json:"totalGrossProfit,omitempty"`
	TotalGrossLoss   fixedpoint.Value `json:"totalGrossLoss,omitempty"`

	SymbolReports []SessionSymbolReport `json:"symbolReports,omitempty"`

	Manifests Manifests `json:"manifests,omitempty"`
}

SummaryReport is the summary of the back-test session

func ReadSummaryReport

func ReadSummaryReport(filename string) (*SummaryReport, error)

Jump to

Keyboard shortcuts

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