dealer

package
v0.0.0-...-a5f00ba Latest Latest
Warning

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

Go to latest
Published: Dec 26, 2023 License: ISC Imports: 26 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// Dormant mode: the AwakenLogger outputs trace logs as info
	// every once in a while.
	Dormant = iota
	// Awaken mode: everything is outputted as-is.
	Awaken = iota
)

Variables

View Source
var (
	ErrNoExchangesLoaded    = errors.New("no exchanges have been loaded")
	ErrExchangeFailedToLoad = errors.New("exchange failed to load")
)
View Source
var (
	ErrAccountIndexOutOfRange = errors.New("no account with this index exists")
	ErrHoldingsNotFound       = errors.New("holdings not found for exchange")
	ErrAccountNotFound        = errors.New("account not found in holdings")
	ErrAssetNotFound          = errors.New("asset not found in account")
	ErrCurrencyNotFound       = errors.New("currency not found in asset")
)
View Source
var (
	ErrStrategyNotFound = errors.New("strategy not found")
	ErrNotStrategy      = errors.New("given object is not a strategy")
)
View Source
var (
	ErrWebsocketNotSupported = errors.New("websocket not supported")
	ErrWebsocketNotEnabled   = errors.New("websocket is not enabled")
)
View Source
var ErrNeedBalancesStrategy = errors.New("Dealer should be configured with balances support")
View Source
var ErrNoAssetType = errors.New("asset type not associated with currency pair")
View Source
var ErrOrdersAlreadyExists = errors.New("order already exists")
View Source
var ErrUnknownEvent = errors.New("unknown event")

Functions

func Code

func Code(e *zerolog.Event, code string)

Code is a helper function to log a code.

func Loop

Loop function is the main entry point for the bot. It is responsible for handling the websocket connection and dispatching events to the appropriate strategy. The Loop function is an infinite loop that blocks until the websocket connection is closed. It is expected to be run in a goroutine.

func ModifyOrder

func ModifyOrder(ctx context.Context, d *Dealer, e exchange.IBotExchange, mod order.Modify) (ans order.ModifyResponse, err error)

ModifyOrder function will execute two steps: modify order on exchange current order status using the submitted ID, after that cancel that order using the same ID. All markers issue when modifying/canceling order also will be made using the same ID it was treated before

func ModifyToCancel

func ModifyToCancel(mod order.Modify) order.Cancel

ModifyToCancel function is responsible for creating a cancel order

func ModifyToSubmit

func ModifyToSubmit(mod order.Modify) order.Submit

ModifyToSubmit function receives a Modify Order which is passed in from the client calls, it creates a Submit order from it. The client calls modifying the order and updating the fetched order if it's done. e.g if an order submitted is filled, the client should change to new order.

func Msg

func Msg(e *zerolog.Event)

Msg is a helper function to log a message.

func OpenWebsocket

func OpenWebsocket(e exchange.IBotExchange) (*stream.Websocket, error)

OpenWebsocket function is responsible for opening a Websocket connection. The `req.Exchange.GetWebsocket` method performs the actual functionality of creating a new Websocket in a struct. Understandably, if a connection can't be opened, the error would be returned. OpenWebsocket checks if the client is sending a query to the interface instance, blocking on a channel, which was a select on a chan while the bolt process has a rule queuing, while the rest of the engine while be blocked on a chan So, non-blocking options were applied to get a non-blocked client and a non-blocked engine.

func Stream

Stream is the main entry point for the bot. It is responsible for opening the websocket connection, and then listening for data on the websocket to come in. When data comes through (this goroutine never dies), it handles all the types of messages available on the websocket. The *exchange.IBotExchange contains the underlying Golang Websocket library, which must be imported with an alias. By using that package with the alias "exchange", we can consolidate the Exchange package into this one without problematic circular imports.

func Ticker

func Ticker(p interface{}) ticker.Price

Ticker takes the input and returns ticker price

func What

func What(e *zerolog.Event, what string)

What is a helper function to log a what.

Types

type Array

type Array interface {
	At(index int) interface{}
	Len() int
	Last() interface{}

	Floats() []float64
	LastFloat() float64
}

Array interface serves to represent a dynamic array of unknown type. For the purpose of this solution we use a `CircularArray` of `string`. Each Historian Object create and own an instance of such a CircularArray. The Dealer holds a totally Stateful History Struct. A `HiStr` keep a pointer to a specific CircularArray Instance. The `HiStr` has a LIFO Queue which stores updates according to their insertion order.

type AugmentConfigFunc

type AugmentConfigFunc func(config *config.Config) error

type AwakenLogger

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

AwakenLogger is a zerolog logger that outputs trace logs as info

func NewAwakenLogger

func NewAwakenLogger(d time.Duration) AwakenLogger

NewAwakenLogger creates a new AwakenLogger.

func (*AwakenLogger) Trace

func (t *AwakenLogger) Trace() *zerolog.Event

Trace logs a trace message.

func (*AwakenLogger) WakeUp

func (t *AwakenLogger) WakeUp()

WakeUp gets the AwakenLogger out of its dormant state for a an amount of time.

type BalancesStrategy

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

BalancesStrategy struct maps exchange names as keys to their respective exchange holdings as values. Using this strategy, we subscribe to a user defined number of tickers and use those to update our holdings. We then atomically update the exchange holding map in our balance strategy struct, and we can read an `ExchangeHoldings` object at any point. Note that this strategy does not order, so stops and take profits can't be engaged. To use it, initialize an exchange and a builder and then simply

func (*BalancesStrategy) Deinit

Deinit should be called when the bot is shutting down or closing functions given by the exchange's API interface.It is used to stop the ticker.

func (*BalancesStrategy) ExchangeHoldings

func (b *BalancesStrategy) ExchangeHoldings(exchangeName string) (*ExchangeHoldings, error)

ExchangeHoldings method returns all the balance from an exchange including all the global account information and information for each asset and account.

func (*BalancesStrategy) Init

Init method loads an initial holdings item and then calls the internal tickers Init. This merges well with the LazyHandler holding the last refresh timestamp since the refresh should already be running when this is called.

func (*BalancesStrategy) OnBalanceChange

func (b *BalancesStrategy) OnBalanceChange(d *Dealer, e exchange.IBotExchange, x account.Change) error

func (*BalancesStrategy) OnFill

func (b *BalancesStrategy) OnFill(d *Dealer, e exchange.IBotExchange, x []fill.Data) error

func (*BalancesStrategy) OnFunding

OnFunding method is not being used because the backtest loads directly from a saved ledger

func (*BalancesStrategy) OnKline

OnKline is called when a new kline is received.

func (*BalancesStrategy) OnModify

func (*BalancesStrategy) OnOrder

func (*BalancesStrategy) OnOrderBook

func (b *BalancesStrategy) OnOrderBook(d *Dealer, e exchange.IBotExchange, x orderbook.Base) error

func (*BalancesStrategy) OnPrice

OnPrice method is called every time a new price is received from the exchange.

func (*BalancesStrategy) OnTrade

func (b *BalancesStrategy) OnTrade(d *Dealer, e exchange.IBotExchange, x []trade.Data) error

func (*BalancesStrategy) OnUnrecognized

func (b *BalancesStrategy) OnUnrecognized(d *Dealer, e exchange.IBotExchange, x interface{}) error

type Builder

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

Builder struct holds state. In this case it specifically has a definition function Augment(). It also stores internal values such as the path the configs will be read from, the closures/recipe function it will use while conditioning config values. Our Augment() will run before the Build() code is called. In this case, the config itself may have been read from a filepath. In this case, our function augments with a value from the dealerBuilder struct/obj. That function is then run, and various further functions that had been defined for this. Finally, if a file wasn't found, one of the directives within our builder will be constructed a new default template as an alternative to the expected input not found (the expected input "initial")

func NewBuilder

func NewBuilder() *Builder

NewBuilder returns a new or configured keep builder NewBuilder function is used to build the Dealer object. When we call `dealer, err := builder.build()` we get a *dealer and an error back.

func (*Builder) Augment

func (b *Builder) Augment(f AugmentConfigFunc) *Builder

Augment augments the exposed functions of the generated service interface, change this to modify the exposed service definition Augment function, which you can change, compiles any code in the go code in this environment upon running application.

func (*Builder) Balances

func (b *Builder) Balances(refresh time.Duration) *Builder

Balances function will set the refresh interval to fetch balances which in our could be 10 seconds for example. This interval will determine how often the bot will make an API call for fetching latest prices. My assumption is that it's done 10 seconds to minimize amount of data fetched in-between trades to reduce fees.

func (Builder) Build

func (b Builder) Build(ctx context.Context) (*Dealer, error)

Build function is used to build the dealer object. When we call `dealer, err := builder.build()` we get a *dealer and an error back.

func (*Builder) CustomExchange

func (b *Builder) CustomExchange(name string, f ExchangeFactory) *Builder

CustomExchange function exports a variable called "CustomExchange", which will be registered in each pair's "ExchangeCreatorFunc". Via *Builder's CustomExchange function we can insert a custom Exchange Creator. Since the name is the only customization we have with this builder, we have to have a factory interface which can instantiate ExchangeCreatorFunc.

func (*Builder) Reporter

func (b *Builder) Reporter(r Reporter) *Builder

Reporter function will add a reporter to the list of reporters.

func (*Builder) Settings

func (b *Builder) Settings(s engine.Settings) *Builder

Settings can be used to construct custom settings for the exchange. Since it is optional, the configuration would only have the parts by being assigned in code.

type CircularArray

type CircularArray struct {
	Offset int
	// contains filtered or unexported fields
}

CircularArray is initialized with the "width" of the array.

func NewCircularArray

func NewCircularArray(n int) CircularArray

NewCircularArray function creates a new circular buffer of a defined size of capacity. The Len function returns the length of the buffer which is the same as the number of observations in a specific window.

func (*CircularArray) At

func (a *CircularArray) At(index int) interface{}

At function returns the n-th element which can be indexed by the external `index` argument. To map this external 0-based index to the underlying 0-based index of the slice, we call a helper method `Index` which will return a wrapped index. Assuming a CircularArray of 100 elements, a call to `At(99)` with a wrapping index of 96 will return the 96th element of the array, wrapped completely around the array as considered as a circle.

func (*CircularArray) Floats

func (a *CircularArray) Floats() []float64

Floats converts each element in the underlying slice to a floating point number.

func (*CircularArray) Index

func (a *CircularArray) Index(i int) int

Index maps an external 0-based index to the corresponding internal index.

func (*CircularArray) Last

func (a *CircularArray) Last() interface{}

Last returns the last element of the underlying slice.

func (*CircularArray) LastFloat

func (a *CircularArray) LastFloat() float64

LastFloat function returns the last element in the underlying slice cast to a floating point number

func (*CircularArray) LastIndex

func (a *CircularArray) LastIndex() int

The LastIndex function returns int value. If the values are all inside of uint values (whose maximum value is (1 << 31) - 1) the must value of offset, which is returned by lastIndex function, would be (1 << 31) - 1. In normal case, the maximum uint value will be (1 << 32) - 1. Then, lastIndex function returns (1 << 32) - 1.

func (*CircularArray) Len

func (a *CircularArray) Len() int

Len function returns the number of elements currently stored. It returns `len(y)` which extracts the length of the underlying slice.

func (*CircularArray) Push

func (a *CircularArray) Push(x interface{})

type CurrencyBalance

type CurrencyBalance struct {
	Currency   currency.Code
	TotalValue float64
	Hold       float64
}

CurrencyBalance struct is an easy way to house the pairs of currency held. struct with our most used currencies. Just with some nice printing methods for the most part.

type Dealer

type Dealer struct {
	Root            RootStrategy
	Settings        engine.Settings
	Config          config.Config
	ExchangeManager engine.ExchangeManager
	// contains filtered or unexported fields
}

Dealer struct holds state. In this case it specifically has a definition function Augment(). It also stores internal values such as the path the configs will be read from, the closures/recipe function it will use while conditioning config values. Our Augment() will run before the Build() code is called. In this case, the config itself may have been read from a filepath. In this case, our function augments with a value from the dealerBuilder struct/obj. That function is then run, and various further functions that had been defined for this. Finally, if a file wasn't found, one of the directives within our builder will be constructed a new default template as an alternative to the expected input not found (the expected input "initial"

func (*Dealer) ActivateAsset

func (bot *Dealer) ActivateAsset(e exchange.IBotExchange, a asset.Item) error

ActivateAsset will activate the asset for the given exchange.

func (*Dealer) ActivatePair

func (bot *Dealer) ActivatePair(e exchange.IBotExchange, a asset.Item, p currency.Pair) error

ActivatePair will activate the pair for the given exchange.

func (*Dealer) AddHistorian

func (bot *Dealer) AddHistorian(
	exchangeName,
	eventName string,
	interval time.Duration,
	stateLength int,
	f func(Array),
) error

func (*Dealer) CancelOrder

func (bot *Dealer) CancelOrder(ctx context.Context, exchangeOrName interface{}, x order.Cancel) error

CancelOrder calls to make an Order.Cancel which includes the giving submitted order, the name to the requested submitted order and the current name of Exchange, calls to it to make Order.Cancel, otherwise return error. It returns the waiting for canceled order if successful, otherwise error. Filters the Orders map if the given Order ID exists and deletes its map from it.

func (*Dealer) GetActiveOrders

func (bot *Dealer) GetActiveOrders(ctx context.Context, exchangeOrName interface{}, request order.MultiOrderRequest) ([]order.Detail, error)

GetActiveOrders function is a wrapper around the GetActiveOrders function in the exchange package.

func (*Dealer) GetEnabledPairAssetType

func (bot *Dealer) GetEnabledPairAssetType(e exchange.IBotExchange, c currency.Pair) (asset.Item, error)

GetEnabledPairAssetType function returns a list of enabled asset types for a given exchange.

func (*Dealer) GetExchangeByName

func (bot *Dealer) GetExchangeByName(name string) (exchange.IBotExchange, error)

GetExchangeByName function returns an exchange interface by name.

func (*Dealer) GetExchanges

func (bot *Dealer) GetExchanges() []exchange.IBotExchange

GetExchanges is a wrapper of GCT's Engine.GetExchanges

func (*Dealer) GetOrderValue

func (bot *Dealer) GetOrderValue(exchangeName, orderID string) (OrderValue, bool)

GetOrderValue function retrieves order details from the given bot's store.

func (*Dealer) ModifyOrder

func (bot *Dealer) ModifyOrder(ctx context.Context, exchangeOrName interface{}, mod order.Modify) (order.ModifyResponse, error)

ModifyOrder method calls the SubmitOrder method then Contains method to check for an exchange name in xs slice. If contains is true, you will return an error since an exchange was reported. If contains is false, you will continue with the execution of the function. CreateOrder method will not be executed if Contains method returns an error.

func (*Dealer) OnOrder

func (bot *Dealer) OnOrder(e exchange.IBotExchange, x order.Detail)

OnOrder function calls the GetOrderValue method to see if an order exists with that dealer. We have a GetValue method in the handler file. We modify the obtained value by setting its UserData to the OnFilled Observer required to perform the appropriate strategy. In n our instance, our order may include two methods. One provides us with a transaction, while the other provides us with profit and loss information (P&L). When we get an order, we set the User data to OnFilledObserver using the Value property and leave the handler code. Within the Handler. OnFilled, we check two criteria to verify whether they are present in Value in order to optimize the strategy's execution.

func (*Dealer) ReportEvent

func (bot *Dealer) ReportEvent(m Metric, labels ...string)

ReportEvent will report an event to the metrics server.

func (*Dealer) ReportLatency

func (bot *Dealer) ReportLatency(m Metric, t time.Time, labels ...string)

ReportLatency will report the latency of the bot to the metrics server.

func (*Dealer) ReportValue

func (bot *Dealer) ReportValue(m Metric, v float64, labels ...string)

ReportValue will report a value to the metrics server

func (*Dealer) Run

func (bot *Dealer) Run(ctx context.Context)

Run is the entry point of all exchange data streams. Strategy.On*() events for a single exchange are invoked from the same thread. Thus, if a strategy deals with multiple exchanges simultaneously, there may be race conditions.

func (*Dealer) SubmitOrder

func (bot *Dealer) SubmitOrder(ctx context.Context, exchangeOrName interface{}, submit order.Submit) (*order.SubmitResponse, error)

SubmitOrder function, simply makes an Order.Submit which contains the giving parameters and the current name of requested Exchange Submit it to the giving requested Exchange, called at the user orders code. It returns the order map response if successful, otherwise error.

func (*Dealer) SubmitOrderUD

func (bot *Dealer) SubmitOrderUD(ctx context.Context, exchangeOrName interface{}, submit order.Submit, userData interface{}) (*order.SubmitResponse, error)

SubmitOrderUD is similar to the SubmitOrder, except that this function also adds the order map into the Orders map and its corresponding ID and name and then return it and its error and additional notes and errors which cause the metric to move asynchronous processing.

func (*Dealer) SubmitOrders

func (bot *Dealer) SubmitOrders(ctx context.Context, e exchange.IBotExchange, xs ...order.Submit) error

SubmitOrders method calls the SubmitOrder method then Contains method to check for an exchage name in xs slice. If contains is true, you will return an error since an exchange was reported. If contains is false, you will continue with the execution of the function. ListOrder method will not be executed if Contains method returns an error.

type ExchangeFactory

type ExchangeFactory interface {
	NewExchangeByName(name string) (exchange.IBotExchange, error)
}

ExchangeFactory defines an interface for creating exchange instances. It abstracts the instantiation process, allowing for flexible and dynamic creation of different exchanges based on a given name.

type ExchangeHoldings

type ExchangeHoldings struct {
	Accounts map[string]SubAccount
}

ExchangeHoldings struct is a struct where we house a map[string]SubAccount. For accounts, we basically house all our accounts now as a string as they are all now connected to gct now as a linked service. To make them easier to reference.

func Holdings

func Holdings(d *Dealer, exchangeName string) (*ExchangeHoldings, error)

Holdings function finds the exchanges balances strategy, then does two things: Looks for an exchange by its name in the holdings map. Returns the holding for the exchange if it's in the map.

func NewExchangeHoldings

func NewExchangeHoldings() *ExchangeHoldings

NewExchangeHoldings function is an easy way to create an empty ExchangeHoldings struct, so we can create an empty struct on startup to avoid us facing gct/goat by ensuring state on startup

func (*ExchangeHoldings) CurrencyBalance

func (h *ExchangeHoldings) CurrencyBalance(accountID string, asset asset.Item, code currency.Code) (CurrencyBalance, error)

CurrencyBalance method is an easy way to get the total value of a currency held.

type GCTConsoleWriter

type GCTConsoleWriter struct{}

GCTConsoleWriter is a zerolog writer that outputs to the console.

func (GCTConsoleWriter) Write

func (c GCTConsoleWriter) Write(p []byte) (n int, err error)

Write implements the Writer interface.

type Historian

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

Historian struct creates an array that is responsible for storing data. The event this struct executes is `OnOrder`, that appends to the array the order. the interval is `OnOrder` is optional; since it returns once every interval epoch is an attribute of the struct, its mutability allows us to isolate the state quirks. The `state` itself is an interface that allows us to replace with different arrays

func NewHistorian

func NewHistorian(interval time.Duration, stateLength int, f func(array Array)) Historian

NewHistorian function above returns a pointer to golang native type Historian, NOT a reference to it. This, in turn, returns a pointer to golang native type CircularArray, NOT a reference to a new instance of a CircularArray.

func (*Historian) Floats

func (u *Historian) Floats() []float64

Floats returns the underlying array, but cast to []float64, for easy sorting/graphing, without any modifications.

func (*Historian) Push

func (u *Historian) Push(x interface{})

Push is called once per update, so it is guaranteed to be executed once per interval. The push function not update the state of the historian

func (*Historian) Update

func (u *Historian) Update(now time.Time, x interface{})

Update function will update the underlying circular array elements and perform a callback when either: we last updated >= interval ago, or the current state is the first state - we can just update and bind everything new.

type HistoryStrategy

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

HistoryStrategy struct is to reduce the amount of data processed by the bot. The idea is to gather the required data points (e.g. OHLCV) and store them in `Historian` units (see `NewHistorian` above) instead of asking exchanges to provide the data directly.

func NewHistoryStrategy

func NewHistoryStrategy() HistoryStrategy

NewHistoryStrategy defines Two maps, one for the History event on the Price field, and one for the Order event.

func (*HistoryStrategy) AddHistorian

func (r *HistoryStrategy) AddHistorian(exchangeName, eventName string, interval time.Duration, stateLength int, f func(array Array)) error

AddHistorian function is called at exchange initialization. First, it creates internal data structures necessary for the history to work. AddHistorian function is very useful when you expect the same event to be triggered constantly over a certain time interval. `onPriceUnits` member is a map of arrays of historians. Each array contains exactly one historian, since every history strategy needs to be attached to a single exchange. `onOrderUnits` member is a map of arrays of historians. Each array contains exactly one historian, since every history strategy needs to be attached to a single exchange.

func (*HistoryStrategy) BindOnPrice

func (r *HistoryStrategy) BindOnPrice(unit *Historian)

func (*HistoryStrategy) Deinit

func (*HistoryStrategy) Init

Init function of the HistoryStrategy registers the onPriceUnits, onOrderUnits, onPriceUnitsPerCurrency, onOrderUnitsPerCurrency collectors.

func (*HistoryStrategy) OnBalanceChange

func (r *HistoryStrategy) OnBalanceChange(d *Dealer, e exchange.IBotExchange, x account.Change) error

func (*HistoryStrategy) OnFill

func (r *HistoryStrategy) OnFill(d *Dealer, e exchange.IBotExchange, x []fill.Data) error

func (*HistoryStrategy) OnFunding

func (*HistoryStrategy) OnKline

func (*HistoryStrategy) OnModify

func (*HistoryStrategy) OnOrder

func (*HistoryStrategy) OnOrderBook

func (r *HistoryStrategy) OnOrderBook(d *Dealer, e exchange.IBotExchange, x orderbook.Base) error

func (*HistoryStrategy) OnPrice

func (*HistoryStrategy) OnTrade

func (r *HistoryStrategy) OnTrade(d *Dealer, e exchange.IBotExchange, x []trade.Data) error

func (*HistoryStrategy) OnUnrecognized

func (r *HistoryStrategy) OnUnrecognized(d *Dealer, e exchange.IBotExchange, x interface{}) error

type LogState

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

LogState keeps track of what the current state is.

func NewLogState

func NewLogState(duration time.Duration) LogState

NewLogState creates a new LogState.

func (*LogState) Awaken

func (s *LogState) Awaken() bool

Awaken returns true if the state is Awaken.

func (*LogState) WakeUp

func (s *LogState) WakeUp()

WakeUp sets the state to Awaken.

type Metric

type Metric int
const (
	// SubmitOrderMetric Submit order metrics.
	SubmitOrderMetric Metric = iota
	SubmitOrderLatencyMetric
	SubmitOrderErrorMetric
	// SubmitBulkOrderMetric Submit bulk orders metrics.
	SubmitBulkOrderMetric
	SubmitBulkOrderLatencyMetric
	// ModifyOrderMetric Modify order metrics.
	ModifyOrderMetric
	ModifyOrderLatencyMetric
	ModifyOrderErrorMetric
	// CancelOrderMetric Cancel order metrics.
	CancelOrderMetric
	CancelOrderLatencyMetric
	CancelOrderErrorMetric
	// CancelAllOrdersMetric Cancel all orders metrics.
	CancelAllOrdersMetric
	CancelAllOrdersLatencyMetric
	CancelAllOrdersErrorMetric
	// GetActiveOrdersMetric Get Active orders metrics.
	GetActiveOrdersMetric
	GetActiveOrdersLatencyMetric
	GetActiveOrdersErrorMetric
	// MaxMetrics this should always be the last one.
	MaxMetrics
)

type OnFilledObserver

type OnFilledObserver interface {
	OnFilled(d *Dealer, e exchange.IBotExchange, orderDetail order.Detail)
}

OnFilledObserver is an interface that responds to each placed order by the dealer. The OnFilled method is expected to perform operations when a trade order is filled.

type OrderKey

type OrderKey struct {
	ExchangeName string
	OrderID      string
}

OrderKey struct implements the `Key` interface of the sync.Map, which used for type assertion of the key

type OrderRegistry

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

OrderRegistry struct that stores two things: The amount of orders in it and the key. It has a single `int` property that represents the amount of orders currently in the registry. The `int` property is an atomic.Int, which is part of the golang's atomic package. It contains the modification of this `int`property that happens at the same time. The modification of an int cannot happen at two places in code in parallel. This provides a safe way to get or update integers from multiple routines, or from goroutines. In this case it’s the inner length field.

func NewOrderRegistry

func NewOrderRegistry() *OrderRegistry

NewOrderRegistry constructs a new OrderRegistry. The function initializes the field atomic.Int32 called length with 0 this means your r.length is incremented after every call of this function.

func (*OrderRegistry) GetOrderValue

func (r *OrderRegistry) GetOrderValue(exchangeName, orderID string) (OrderValue, bool)

GetOrderValue initially verifies that the exchange name and order ID exist in the OrderRegistry. This results in the `want`, and `ok` variables and assignment then return if that's the case. If it's not, then it's safe for r.values. LoadOrStore to return a "new" order value. It will create a new OrderValue with the input `UserData` and then load the `SubmitResponse` from the `DecodedUpdates` channel. If that should fail, its logged

func (*OrderRegistry) Length

func (r *OrderRegistry) Length() int

func (*OrderRegistry) Store

func (r *OrderRegistry) Store(exchangeName string, response order.SubmitResponse, userData interface{}) bool

Store stores the global order data to the `OrderRegistry`. The code looks like it should just wrap structs around another struct, that is not the case. First, it checks if an order with the same exchange name and order ID already exist, if not the order value will be stored in the `OrderRegistry` and `returned` will `true`. Secondly, the `loaded` argument is returned. This `loaded` argument is needed to see if the order has already been added to the `OrderRegistry` and therefore we need to run the code again.

type OrderValue

type OrderValue struct {
	SubmitResponse order.SubmitResponse
	UserData       interface{}
}

OrderValue struct holds two fields, which are both stored under the `OrderValue` struct. The first field is the `SubmitResponse` which comes from `Submit` function. It's the response returned from the webserver of each exchange. It includes data like whether or not the order is placed, the order ID (in case the order is placed), the creation timestamp, the creation amount (unit), etc. It also contains all exchange-specific error messages under `Error()`.

type Reporter

type Reporter interface {
	// Event metrics in a single occurrence
	Event(m Metric, labels ...string)
	// Latency metrics provide visibility over latencies
	Latency(m Metric, d time.Duration, labels ...string)
	// Value metrics provide visibility over arbitrary value
	Value(m Metric, v float64, labels ...string)
}

Reporter interface is implemented by the clients that wish to report their metrics for this library.

type RootStrategy

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

RootStrategy is a struct that contains a map of strategies. The map is a sync.Map, which is a thread safe map. The map is initialized with a sync.Map{} and then we can add strategies to it. The map is a map of string to Strategy. The string is the name of the strategy and the Strategy is the implementation of the strategy.

func NewRootStrategy

func NewRootStrategy() RootStrategy

NewRootStrategy returns the RootStrategy object. The RootStrategy object has several functions (each). creating a RootStrategy variable which is an object. Then we are iterating through each of the additional strategies and adding them to the NewRootStrategy, so they are available as the final implementation is created after they have been created

func (*RootStrategy) Add

func (m *RootStrategy) Add(name string, s Strategy)

Add function takes a string that identifies a implementation of the Strategy, and the implementation of the implementation of the Strategy implementation itself. It stores an implementation of a strategy implementation under a string named after the strategy implementation. Which resolves to the correct implementation of the Strategy.

func (*RootStrategy) Deinit

func (m *RootStrategy) Deinit(d *Dealer, e exchange.IBotExchange) error

Deinit deinitializes strategies in a specific Dealer struct For each strategy in a Dealer, calls Strategy.Deinit()

func (*RootStrategy) Delete

func (m *RootStrategy) Delete(name string) (Strategy, error)

Delete the Strategy specified by name. You get an object, get the interface's value, and then determine the interface's value.

func (*RootStrategy) Get

func (m *RootStrategy) Get(name string) (Strategy, error)

Get returns the strategy with the given name

func (*RootStrategy) Init

Init function loops through each of the imported Strategy implementations and calls their init functions to initialize them. Ordering of implementations is important and if an implementation depends on something another requires you should order the strategy implementations.

func (*RootStrategy) OnBalanceChange

func (m *RootStrategy) OnBalanceChange(d *Dealer, e exchange.IBotExchange, x account.Change) error

OnBalanceChange iterates over each strategy, calling OnBalanceChange, logging an error if any fail Returns nil on success, or Function specific error on failure

func (*RootStrategy) OnFill

func (m *RootStrategy) OnFill(d *Dealer, e exchange.IBotExchange, x []fill.Data) error

func (*RootStrategy) OnFunding

OnFunding function for the Root strategy. The first line of the function is to call the same function on each_ it is the interface method for the Strategy. A new function is called, which is more of an interface for the Strategy called OnFunding. Which allows the user to choose how they want to pass this event to the strategy.

func (*RootStrategy) OnKline

OnKline listens to the Kline stream data events and execute optional action

func (*RootStrategy) OnModify

func (m *RootStrategy) OnModify(d *Dealer, e exchange.IBotExchange, x order.Modify) error

OnModify is invoked when an order is modified. The arguments passed are the original user message

func (*RootStrategy) OnOrder

func (m *RootStrategy) OnOrder(d *Dealer, e exchange.IBotExchange, x order.Detail) error

OnOrder is called when changes occur to a specific order

func (*RootStrategy) OnOrderBook

func (m *RootStrategy) OnOrderBook(d *Dealer, e exchange.IBotExchange, x orderbook.Base) error

OnOrderBook is called when initial orderbook is created or if the bids or asks change Must pass in Dealer that created this strategy. Also pass in the Exchange used by the strategy Call this function once per Strategy

func (*RootStrategy) OnPrice

func (m *RootStrategy) OnPrice(d *Dealer, e exchange.IBotExchange, x ticker.Price) error

The OnPrice implementation of the Strategy is different from above. It does not let the user choose how they want to use this information and passes all the information to the specific implementation of that data.

func (*RootStrategy) OnTrade

func (m *RootStrategy) OnTrade(d *Dealer, e exchange.IBotExchange, x []trade.Data) error

func (*RootStrategy) OnUnrecognized

func (m *RootStrategy) OnUnrecognized(d *Dealer, e exchange.IBotExchange, x interface{}) error

OnUnrecognized is called on unrecognized data

type Slots

type Slots struct {
	OnFilledSlot func(d *Dealer, e exchange.IBotExchange, orderDetail order.Detail)
}

Slots is a struct that contains an OnFilled function pointer. as the OnFilled method in the OnFilledObserver interface. This allows for customizable behavior when an order gets filled.

func (Slots) OnFilled

func (s Slots) OnFilled(d *Dealer, e exchange.IBotExchange, orderDetail order.Detail)

OnFilled is invoked with the placed order and the exchange. It retrieves the original order details and can be used as a source of data for reconciliation. If this strategy is acceptable per exchange, all orders are needed.

type Strategy

type Strategy interface {
	Init(ctx context.Context, d *Dealer, e exchange.IBotExchange) error
	OnFunding(d *Dealer, e exchange.IBotExchange, x stream.FundingData) error
	OnPrice(d *Dealer, e exchange.IBotExchange, x ticker.Price) error
	OnKline(d *Dealer, e exchange.IBotExchange, x stream.KlineData) error
	OnOrderBook(d *Dealer, e exchange.IBotExchange, x orderbook.Base) error
	OnOrder(d *Dealer, e exchange.IBotExchange, x order.Detail) error
	OnModify(d *Dealer, e exchange.IBotExchange, x order.Modify) error
	OnBalanceChange(d *Dealer, e exchange.IBotExchange, x account.Change) error
	OnTrade(d *Dealer, e exchange.IBotExchange, x []trade.Data) error
	OnFill(d *Dealer, e exchange.IBotExchange, x []fill.Data) error
	OnUnrecognized(d *Dealer, e exchange.IBotExchange, x interface{}) error
	Deinit(d *Dealer, e exchange.IBotExchange) error
}

Strategy is an interface and defines all function needed for a user defined strategy. The RootStrategy provides a way to create and use strategies and action according to given strategies. Strategy interface defines all the functions that must be implemented in order for the strategy to operate correctly. It has "On" functions and a data type that comprises keys and values that may be strings, interfaces, or anything else. While this may seem to be a constraint on the execution of your approach, you may use the OnUnrecognized function to implement anything at an experimental stage.

func NewBalancesStrategy

func NewBalancesStrategy(refreshRate time.Duration) Strategy

NewBalancesStrategy function creates an instance of the BalancesStrategy struct. In turn, the BalancesStrategy struct creates a TickFunc method as a `ticker.Ticker.TickFunc` Then assigns that TickFunc function to the TickerStrategy object that is to be used later.

type SubAccount

type SubAccount struct {
	ID       string
	Balances map[asset.Item]map[currency.Code]CurrencyBalance
}

SubAccount struct is an easy way to group our connected accounts. To hold all connected exchanges.

type TickerStrategy

type TickerStrategy struct {
	Interval time.Duration
	TickFunc func(d *Dealer, e exchange.IBotExchange)
	// contains filtered or unexported fields
}

TickerStrategy is a struct that implements the TickerStrategy interface. Interval is the time interval between tickers. TickFunc is a function that returns a ticker. tickers is a map of tickers.

func (*TickerStrategy) Deinit

func (s *TickerStrategy) Deinit(d *Dealer, e exchange.IBotExchange) error

Deinit stops the ticker for the given Exchange.

func (*TickerStrategy) Init

Init will call our ticker code on its own. We can easily build a reoccurring ticker using the information in the ExchangeConnections struct by establishing a goroutine runtime. The runtime clock enables us to manage time without the need for a goroutine.

func (*TickerStrategy) OnBalanceChange

func (s *TickerStrategy) OnBalanceChange(d *Dealer, e exchange.IBotExchange, x account.Change) error

OnBalanceChange implements the TickerStrategy interface function. Used to trigger an action for an already running ticker

func (*TickerStrategy) OnFill

func (s *TickerStrategy) OnFill(d *Dealer, e exchange.IBotExchange, x []fill.Data) error

func (*TickerStrategy) OnFunding

OnFunding - entrypoint for the strategy triggered on funding data Called if OnMsgHandlerMsg(Data(fundingData) trigger returns true

func (*TickerStrategy) OnKline

OnKline is called when tick data is received

func (*TickerStrategy) OnModify

OnModify updates modify order

func (*TickerStrategy) OnOrder

OnOrder manipulates the dealers orderbook given a new incoming order x order.Detail is the new order

func (*TickerStrategy) OnOrderBook

func (s *TickerStrategy) OnOrderBook(d *Dealer, e exchange.IBotExchange, x orderbook.Base) error

OnOrderBook is triggered when API receives orderbook update

func (*TickerStrategy) OnPrice

OnPrice is called when price announcement or updates are received.

func (*TickerStrategy) OnTrade

func (s *TickerStrategy) OnTrade(d *Dealer, e exchange.IBotExchange, x []trade.Data) error

func (*TickerStrategy) OnUnrecognized

func (s *TickerStrategy) OnUnrecognized(d *Dealer, e exchange.IBotExchange, x interface{}) error

OnUnrecognized is a function that is called when an unsupported data type is given and most likely indicates a parsing error has occurred with Exchanges

type Trade

type Trade struct {
	Timestamp     time.Time
	BaseCurrency  string
	QuoteCurrency string
	OrderID       string
	AveragePrice  float64
	Quantity      float64
	Fee           float64
	FeeCurrency   string
}

Jump to

Keyboard shortcuts

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