statistics

package
v0.0.0-...-ca9efe7 Latest Latest
Warning

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

Go to latest
Published: May 17, 2024 License: MIT Imports: 25 Imported by: 6

README

GoCryptoTrader Backtester: Statistics package

Build Status Software License GoDoc Coverage Status Go Report Card

This statistics package is part of the GoCryptoTrader codebase.

This is still in active development

You can track ideas, planned features and what's in progress on this Trello board: https://trello.com/b/ZAhMhpOy/gocryptotrader.

Join our slack to discuss all things related to GoCryptoTrader! GoCryptoTrader Slack

Statistics package overview

The statistics package is used for storing all relevant data over the course of a GoCryptoTrader Backtesting run. All types of events are tracked by exchange, asset and currency pair. When multiple currencies are included in your strategy, the statistics package will be able to calculate which exchange asset currency pair has performed the best, along with the biggest drop downs in the market.

It can calculate the following:

  • Calmar ratio
  • Information ratio
  • Sharpe ratio
  • Sortino ratio
  • CAGR
  • Drawdowns, both the biggest and longest
  • Whether the strategy outperformed the market
  • If the strategy made a profit

Ratios

Ratio Description A good range
Calmar ratio It is a function of the fund's average compounded annual rate of return versus its maximum drawdown. The higher the Calmar ratio, the better it performed on a risk-adjusted basis during the given time frame, which is mostly commonly set at 36 months 3.0 to 5.0
Information ratio It is a measurement of portfolio returns beyond the returns of a benchmark, usually an index, compared to the volatility of those returns. The ratio is often used as a measure of a portfolio manager's level of skill and ability to generate excess returns relative to a benchmark 0.40-0.60. Any positive number means that it has beaten the benchmark
Sharpe ratio The Sharpe Ratio is a financial metric often used by investors when assessing the performance of investment management products and professionals. It consists of taking the excess return of the portfolio, relative to the risk-free rate, and dividing it by the standard deviation of the portfolio's excess returns Any Sharpe ratio greater than 1.0 is good. Higher than 2.0 is very good. 3.0 or higher is excellent. Under 1.0 is sub-optimal
Sortino ratio The Sortino ratio measures the risk-adjusted return of an investment asset, portfolio, or strategy. It is a modification of the Sharpe ratio but penalizes only those returns falling below a user-specified target or required rate of return, while the Sharpe ratio penalizes both upside and downside volatility equally The higher the better, but > 2 is considered good
Compound annual growth rate Compound annual growth rate is the rate of return that would be required for an investment to grow from its beginning balance to its ending balance, assuming the profits were reinvested at the end of each year of the investment’s lifespan Any positive number

Arithmetic or versus geometric?

Both! We calculate ratios where an average is required using both types. The reasoning for using either is debated by finance and mathematicians. This is a good breakdown of both, but here is an extra simple table

Average type A reason to use it
Arithmetic The arithmetic mean is the average of a sum of numbers, which reflects the central tendency of the position of the numbers
Geometric The geometric mean differs from the arithmetic average, or arithmetic mean, in how it is calculated because it takes into account the compounding that occurs from period to period. Because of this, investors usually consider the geometric mean a more accurate measure of returns than the arithmetic mean

USD total tracking

If the strategy config setting DisableUSDTracking is false, then the GoCryptoTrader Backtester will automatically retrieve USD data that matches your backtesting currencies, eg pair BTC/LTC will track BTC/USD and LTC/USD as well. This allows for tracking overall strategic performance against one currency. This can allow for much easier performance calculations and comparisons

Please click GoDocs chevron above to view current GoDoc information for this package

Contribution

Please feel free to submit any pull requests or suggest any desired features to be added.

When submitting a PR, please abide by our coding guidelines:

  • Code must adhere to the official Go formatting guidelines (i.e. uses gofmt).
  • Code must be documented adhering to the official Go commentary guidelines.
  • Code must adhere to our coding style.
  • Pull requests need to be based on and opened against the master branch.

Donations

If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:

bc1qk0jareu4jytc0cfrhr5wgshsq8282awpavfahc

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrAlreadyProcessed occurs when an event has already been processed
	ErrAlreadyProcessed = errors.New("this event has been processed already")
)

Functions

This section is empty.

Types

type CurrencyPairStatistic

type CurrencyPairStatistic struct {
	Exchange       string
	Asset          asset.Item
	Currency       currency.Pair
	UnderlyingPair currency.Pair `json:"linked-spot-currency"`

	ShowMissingDataWarning       bool `json:"-"`
	IsStrategyProfitable         bool `json:"is-strategy-profitable"`
	DoesPerformanceBeatTheMarket bool `json:"does-performance-beat-the-market"`

	BuyOrders   int64 `json:"buy-orders"`
	SellOrders  int64 `json:"sell-orders"`
	TotalOrders int64 `json:"total-orders"`

	StartingClosePrice   ValueAtTime `json:"starting-close-price"`
	EndingClosePrice     ValueAtTime `json:"ending-close-price"`
	LowestClosePrice     ValueAtTime `json:"lowest-close-price"`
	HighestClosePrice    ValueAtTime `json:"highest-close-price"`
	HighestUnrealisedPNL ValueAtTime `json:"highest-unrealised-pnl"`
	LowestUnrealisedPNL  ValueAtTime `json:"lowest-unrealised-pnl"`
	HighestRealisedPNL   ValueAtTime `json:"highest-realised-pnl"`
	LowestRealisedPNL    ValueAtTime `json:"lowest-realised-pnl"`

	MarketMovement               decimal.Decimal `json:"market-movement"`
	StrategyMovement             decimal.Decimal `json:"strategy-movement"`
	UnrealisedPNL                decimal.Decimal `json:"unrealised-pnl"`
	RealisedPNL                  decimal.Decimal `json:"realised-pnl"`
	CompoundAnnualGrowthRate     decimal.Decimal `json:"compound-annual-growth-rate"`
	TotalAssetValue              decimal.Decimal `json:"total-asset-value"`
	TotalFees                    decimal.Decimal `json:"total-fees"`
	TotalValueLostToVolumeSizing decimal.Decimal `json:"total-value-lost-to-volume-sizing"`
	TotalValueLostToSlippage     decimal.Decimal `json:"total-value-lost-to-slippage"`
	TotalValueLost               decimal.Decimal `json:"total-value-lost"`

	Events []DataAtOffset `json:"-"`

	MaxDrawdown           Swing               `json:"max-drawdown,omitempty"`
	HighestCommittedFunds ValueAtTime         `json:"highest-committed-funds"`
	GeometricRatios       *Ratios             `json:"geometric-ratios"`
	ArithmeticRatios      *Ratios             `json:"arithmetic-ratios"`
	InitialHoldings       holdings.Holding    `json:"initial-holdings-holdings"`
	FinalHoldings         holdings.Holding    `json:"final-holdings"`
	FinalOrders           compliance.Snapshot `json:"final-orders"`
}

CurrencyPairStatistic Holds all events and statistics relevant to an exchange, asset type and currency pair

func (*CurrencyPairStatistic) CalculateResults

func (c *CurrencyPairStatistic) CalculateResults(riskFreeRate decimal.Decimal) error

CalculateResults calculates all statistics for the exchange, asset, currency pair

func (*CurrencyPairStatistic) PrintResults

func (c *CurrencyPairStatistic) PrintResults(e string, a asset.Item, p currency.Pair, usingExchangeLevelFunding bool) error

PrintResults outputs all calculated statistics to the command line

type CurrencyStats

type CurrencyStats interface {
	TotalEquityReturn() (decimal.Decimal, error)
	MaxDrawdown() Swing
	LongestDrawdown() Swing
	SharpeRatio(decimal.Decimal) decimal.Decimal
	SortinoRatio(decimal.Decimal) decimal.Decimal
}

CurrencyStats defines what is expected in order to calculate statistics based on an exchange, asset type and currency pair

type DataAtOffset

type DataAtOffset struct {
	Offset             int64
	ClosePrice         decimal.Decimal
	Time               time.Time
	Holdings           holdings.Holding
	ComplianceSnapshot *compliance.Snapshot
	DataEvent          data.Event
	SignalEvent        signal.Event
	OrderEvent         order.Event
	FillEvent          fill.Event
	PNL                portfolio.IPNL
}

DataAtOffset is used to hold all event information at a time interval

type FinalResultsHolder

type FinalResultsHolder struct {
	Exchange         string          `json:"exchange"`
	Asset            asset.Item      `json:"asset"`
	Pair             currency.Pair   `json:"currency"`
	MaxDrawdown      Swing           `json:"max-drawdown"`
	MarketMovement   decimal.Decimal `json:"market-movement"`
	StrategyMovement decimal.Decimal `json:"strategy-movement"`
}

FinalResultsHolder holds important stats about a currency's performance

type FundingItemStatistics

type FundingItemStatistics struct {
	ReportItem *funding.ReportItem `json:"-"`
	// USD stats
	StartingClosePrice       ValueAtTime     `json:"starting-close-price"`
	EndingClosePrice         ValueAtTime     `json:"ending-close-price"`
	LowestClosePrice         ValueAtTime     `json:"lowest-close-price"`
	HighestClosePrice        ValueAtTime     `json:"highest-close-price"`
	MarketMovement           decimal.Decimal `json:"market-movement"`
	StrategyMovement         decimal.Decimal `json:"strategy-movement"`
	DidStrategyBeatTheMarket bool            `json:"did-strategy-beat-the-market"`
	RiskFreeRate             decimal.Decimal `json:"risk-free-rate"`
	CompoundAnnualGrowthRate decimal.Decimal `json:"compound-annual-growth-rate"`
	BuyOrders                int64           `json:"buy-orders"`
	SellOrders               int64           `json:"sell-orders"`
	TotalOrders              int64           `json:"total-orders"`
	MaxDrawdown              Swing           `json:"max-drawdown"`
	HighestCommittedFunds    ValueAtTime     `json:"highest-committed-funds"`
	// CollateralPair stats
	IsCollateral      bool        `json:"is-collateral"`
	InitialCollateral ValueAtTime `json:"initial-collateral"`
	FinalCollateral   ValueAtTime `json:"final-collateral"`
	HighestCollateral ValueAtTime `json:"highest-collateral"`
	LowestCollateral  ValueAtTime `json:"lowest-collateral"`
	// Contracts
	LowestHoldings  ValueAtTime `json:"lowest-holdings"`
	HighestHoldings ValueAtTime `json:"highest-holdings"`
	InitialHoldings ValueAtTime `json:"initial-holdings"`
	FinalHoldings   ValueAtTime `json:"final-holdings"`
}

FundingItemStatistics holds statistics for funding items

func CalculateIndividualFundingStatistics

func CalculateIndividualFundingStatistics(disableUSDTracking bool, reportItem *funding.ReportItem, relatedStats []relatedCurrencyPairStatistics) (*FundingItemStatistics, error)

CalculateIndividualFundingStatistics calculates statistics for an individual report item

type FundingStatistics

type FundingStatistics struct {
	Report             *funding.Report         `json:"-"`
	Items              []FundingItemStatistics `json:"funding-item-statistics"`
	TotalUSDStatistics *TotalFundingStatistics `json:"total-usd-statistics"`
}

FundingStatistics stores all funding related statistics

func CalculateFundingStatistics

func CalculateFundingStatistics(funds funding.IFundingManager, currStats map[key.ExchangePairAsset]*CurrencyPairStatistic, riskFreeRate decimal.Decimal, interval gctkline.Interval) (*FundingStatistics, error)

CalculateFundingStatistics calculates funding statistics for total USD strategy results along with individual funding item statistics

func (*FundingStatistics) PrintResults

func (f *FundingStatistics) PrintResults(wasAnyDataMissing bool) error

PrintResults outputs all calculated funding statistics to the command line

type Handler

type Handler interface {
	SetStrategyName(string)
	SetEventForOffset(common.Event) error
	AddHoldingsForTime(*holdings.Holding) error
	AddComplianceSnapshotForTime(*compliance.Snapshot, common.Event) error
	CalculateAllResults() error
	Reset() error
	Serialise() (string, error)
	AddPNLForTime(*portfolio.PNLSummary) error
	CreateLog(common.Event) (string, error)
}

Handler interface details what a statistic is expected to do

type Ratios

type Ratios struct {
	SharpeRatio      decimal.Decimal `json:"sharpe-ratio"`
	SortinoRatio     decimal.Decimal `json:"sortino-ratio"`
	InformationRatio decimal.Decimal `json:"information-ratio"`
	CalmarRatio      decimal.Decimal `json:"calmar-ratio"`
}

Ratios stores all the ratios used for statistics

func CalculateRatios

func CalculateRatios(benchmarkRates, returnsPerCandle []decimal.Decimal, riskFreeRatePerCandle decimal.Decimal, maxDrawdown *Swing, logMessage string) (arithmeticStats, geometricStats *Ratios, err error)

CalculateRatios creates arithmetic and geometric ratios from funding or currency pair data

type ResultEvent

type ResultEvent struct {
	Time time.Time `json:"time"`
}

ResultEvent stores the time

type ResultTransactions

type ResultTransactions struct {
	Time      time.Time       `json:"time"`
	Direction gctorder.Side   `json:"direction"`
	Price     decimal.Decimal `json:"price"`
	Amount    decimal.Decimal `json:"amount"`
	Reason    string          `json:"reason,omitempty"`
}

ResultTransactions stores details on a transaction

type Results

type Results struct {
	Pair              string               `json:"pair"`
	TotalEvents       int                  `json:"totalEvents"`
	TotalTransactions int                  `json:"totalTransactions"`
	Events            []ResultEvent        `json:"events"`
	Transactions      []ResultTransactions `json:"transactions"`
	StrategyName      string               `json:"strategyName"`
}

Results holds some statistics on results

type Statistic

type Statistic struct {
	StrategyName                string                                           `json:"strategy-name"`
	StrategyDescription         string                                           `json:"strategy-description"`
	StrategyNickname            string                                           `json:"strategy-nickname"`
	StrategyGoal                string                                           `json:"strategy-goal"`
	StartDate                   time.Time                                        `json:"start-date"`
	EndDate                     time.Time                                        `json:"end-date"`
	CandleInterval              gctkline.Interval                                `json:"candle-interval"`
	RiskFreeRate                decimal.Decimal                                  `json:"risk-free-rate"`
	ExchangeAssetPairStatistics map[key.ExchangePairAsset]*CurrencyPairStatistic `json:"-"`
	CurrencyStatistics          []*CurrencyPairStatistic                         `json:"currency-statistics"`
	TotalBuyOrders              int64                                            `json:"total-buy-orders"`
	TotalLongOrders             int64                                            `json:"total-long-orders"`
	TotalShortOrders            int64                                            `json:"total-short-orders"`
	TotalSellOrders             int64                                            `json:"total-sell-orders"`
	TotalOrders                 int64                                            `json:"total-orders"`
	BiggestDrawdown             *FinalResultsHolder                              `json:"biggest-drawdown,omitempty"`
	BestStrategyResults         *FinalResultsHolder                              `json:"best-start-results,omitempty"`
	BestMarketMovement          *FinalResultsHolder                              `json:"best-market-movement,omitempty"`
	WasAnyDataMissing           bool                                             `json:"was-any-data-missing"`
	FundingStatistics           *FundingStatistics                               `json:"funding-statistics"`
	FundManager                 funding.IFundingManager                          `json:"-"`
	HasCollateral               bool                                             `json:"has-collateral"`
}

Statistic holds all statistical information for a backtester run, from drawdowns to ratios. Any currency specific information is handled in currencystatistics

func (*Statistic) AddComplianceSnapshotForTime

func (s *Statistic) AddComplianceSnapshotForTime(c *compliance.Snapshot, e common.Event) error

AddComplianceSnapshotForTime adds the compliance snapshot to the statistics at the time period

func (*Statistic) AddHoldingsForTime

func (s *Statistic) AddHoldingsForTime(h *holdings.Holding) error

AddHoldingsForTime adds all holdings to the statistics at the time period

func (*Statistic) AddPNLForTime

func (s *Statistic) AddPNLForTime(pnl *portfolio.PNLSummary) error

AddPNLForTime stores PNL data for tracking purposes

func (*Statistic) CalculateAllResults

func (s *Statistic) CalculateAllResults() error

CalculateAllResults calculates the statistics of all exchange asset pair holdings, orders, ratios and drawdowns

func (*Statistic) CreateLog

func (s *Statistic) CreateLog(data common.Event) (string, error)

CreateLog renders a string log depending on what events are populated at a given offset. Can render logs live, or at the end of a backtesting run

func (*Statistic) GetBestMarketPerformer

func (s *Statistic) GetBestMarketPerformer(results []FinalResultsHolder) *FinalResultsHolder

GetBestMarketPerformer returns the best final market movement

func (*Statistic) GetBestStrategyPerformer

func (s *Statistic) GetBestStrategyPerformer(results []FinalResultsHolder) *FinalResultsHolder

GetBestStrategyPerformer returns the best performing strategy result

func (*Statistic) GetTheBiggestDrawdownAcrossCurrencies

func (s *Statistic) GetTheBiggestDrawdownAcrossCurrencies(results []FinalResultsHolder) *FinalResultsHolder

GetTheBiggestDrawdownAcrossCurrencies returns the biggest drawdown across all currencies in a backtesting run

func (*Statistic) PrintAllEventsChronologically

func (s *Statistic) PrintAllEventsChronologically()

PrintAllEventsChronologically outputs all event details in the CMD rather than separated by exchange, asset and currency pair, it's grouped by time to allow a clearer picture of events

func (*Statistic) PrintTotalResults

func (s *Statistic) PrintTotalResults()

PrintTotalResults outputs all results to the CMD

func (*Statistic) Reset

func (s *Statistic) Reset() error

Reset returns the struct to defaults

func (*Statistic) Serialise

func (s *Statistic) Serialise() (string, error)

Serialise outputs the Statistic struct in json

func (*Statistic) SetEventForOffset

func (s *Statistic) SetEventForOffset(ev common.Event) error

SetEventForOffset sets up the big map for to store important data at each time interval

func (*Statistic) SetStrategyName

func (s *Statistic) SetStrategyName(name string)

SetStrategyName sets the name for statistical identification

type Swing

type Swing struct {
	Highest          ValueAtTime     `json:"highest"`
	Lowest           ValueAtTime     `json:"lowest"`
	DrawdownPercent  decimal.Decimal `json:"drawdown"`
	IntervalDuration int64           `json:"interval-duration"`
}

Swing holds a drawdown

func CalculateBiggestEventDrawdown

func CalculateBiggestEventDrawdown(closePrices []data.Event) (Swing, error)

CalculateBiggestEventDrawdown calculates the biggest drawdown using a slice of DataEvents

func CalculateBiggestValueAtTimeDrawdown

func CalculateBiggestValueAtTimeDrawdown(closePrices []ValueAtTime, interval gctkline.Interval) (Swing, error)

CalculateBiggestValueAtTimeDrawdown calculates the biggest drawdown using a slice of ValueAtTimes

type TotalFundingStatistics

type TotalFundingStatistics struct {
	HoldingValues            []ValueAtTime   `json:"-"`
	HighestHoldingValue      ValueAtTime     `json:"highest-holding-value"`
	LowestHoldingValue       ValueAtTime     `json:"lowest-holding-value"`
	BenchmarkMarketMovement  decimal.Decimal `json:"benchmark-market-movement"`
	RiskFreeRate             decimal.Decimal `json:"risk-free-rate"`
	CompoundAnnualGrowthRate decimal.Decimal `json:"compound-annual-growth-rate"`
	MaxDrawdown              Swing           `json:"max-drawdown"`
	GeometricRatios          *Ratios         `json:"geometric-ratios"`
	ArithmeticRatios         *Ratios         `json:"arithmetic-ratios"`
	DidStrategyBeatTheMarket bool            `json:"did-strategy-beat-the-market"`
	DidStrategyMakeProfit    bool            `json:"did-strategy-make-profit"`
	HoldingValueDifference   decimal.Decimal `json:"holding-value-difference"`
}

TotalFundingStatistics holds values for overall statistics for funding items

type ValueAtTime

type ValueAtTime struct {
	Time  time.Time       `json:"time"`
	Value decimal.Decimal `json:"value"`
	Set   bool            `json:"-"`
}

ValueAtTime is an individual iteration of price at a time

Jump to

Keyboard shortcuts

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