broker

package module
v0.1.6 Latest Latest
Warning

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

Go to latest
Published: Mar 3, 2026 License: MIT Imports: 22 Imported by: 0

README

broker

Unified Go facade over Binance, Bybit, and dYdX.

Goals:

  • One interface for balances, orders, candles, ping, and server time.
  • Unified domain models and error types.
  • Same method names and signatures across exchanges.

Install

go get github.com/svanichkin/broker

Quick start

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/svanichkin/broker"
)

func main() {
	ctx := context.Background()
	ex, err := broker.NewExchange(ctx, broker.Config{
		Exchange:  broker.ExchangeBinance,
		APIKey:    "YOUR_KEY",
		APISecret: "YOUR_SECRET",
		Timeout:   10 * time.Second,
	})
	if err != nil {
		panic(err)
	}

	if err := ex.Ping(ctx); err != nil {
		panic(err)
	}

	now, err := ex.ServerTime(ctx)
	if err != nil {
		panic(err)
	}
	fmt.Println("server time:", now)
}

Config

cfg := broker.Config{
	Exchange:  broker.ExchangeBybit, // or broker.ExchangeBinance / broker.ExchangeDydx
	APIKey:    "YOUR_KEY",
	APISecret: "YOUR_SECRET",
	Passphrase: "YOUR_PASSPHRASE", // required for dYdX
	BaseURL:   "",                // optional override
	Timeout:   10 * time.Second,

	// dYdX-only fields
	EthereumAddress:          "0x...",
	StarkPublicKey:           "...",
	StarkPrivateKey:          "...",
	StarkPublicKeyYCoordinate: "...",
}

Create facade or exchange:

fx, err := broker.New(ctx, cfg)      // returns *broker.Facade
ex, err := broker.NewExchange(ctx, cfg) // returns broker.Exchange

Exchange interface

type Exchange interface {
	Name() ExchangeName
	Capabilities() Capabilities

	SubscribeCandles(ctx context.Context, symbol string, interval CandleInterval) (<-chan Candle, <-chan error)
	GetCandles(ctx context.Context, symbol string, interval CandleInterval, start, end time.Time) ([]Candle, error)

	GetBalances(ctx context.Context) ([]Balance, error)
	ListOpenOrders(ctx context.Context, symbol string) ([]Order, error)
	ListOrders(ctx context.Context, symbol string, status OrderStatus) ([]Order, error)
	GetFeeRates(ctx context.Context, symbol string, market MarketType) (FeeRates, error)
	PlaceOrder(ctx context.Context, req PlaceOrderRequest) (Order, error)
	CancelOrder(ctx context.Context, symbol, orderID string) error
	GetOrder(ctx context.Context, symbol, orderID string) (Order, error)

	Ping(ctx context.Context) error
	ServerTime(ctx context.Context) (time.Time, error)
}

API reference

Enums
type ExchangeName string
const (
	ExchangeBinance ExchangeName = "Binance"
	ExchangeBybit   ExchangeName = "Bybit"
	ExchangeDydx    ExchangeName = "Dydx"
)

type CandleInterval string
const (
	CandleIntervalTick   CandleInterval = "tick"
	CandleIntervalSecond CandleInterval = "1s"
	CandleIntervalMinute CandleInterval = "1m"
	CandleIntervalHour   CandleInterval = "1h"
	CandleIntervalDay    CandleInterval = "1d"
)

type MarketType string
const (
	MarketSpot        MarketType = "spot"
	MarketDerivatives MarketType = "derivatives"
)

type OrderStatus string
const (
	OrderStatusNew             OrderStatus = "NEW"
	OrderStatusPartiallyFilled OrderStatus = "PARTIALLY_FILLED"
	OrderStatusFilled          OrderStatus = "FILLED"
	OrderStatusCanceled        OrderStatus = "CANCELED"
	OrderStatusRejected        OrderStatus = "REJECTED"
)

type OrderSide string
const (
	OrderSideBuy  OrderSide = "BUY"
	OrderSideSell OrderSide = "SELL"
)

type OrderType string
const (
	OrderTypeLimit  OrderType = "LIMIT"
	OrderTypeMarket OrderType = "MARKET"
)

type TimeInForce string
const (
	TimeInForceGTC TimeInForce = "GTC"
	TimeInForceIOC TimeInForce = "IOC"
	TimeInForceFOK TimeInForce = "FOK"
)
Structs
type Capabilities struct {
	Spot        bool
	Derivatives bool
	Streaming   bool
}

type Config struct {
	Exchange   ExchangeName // required
	APIKey     string
	APISecret  string
	Passphrase string        // dYdX only
	BaseURL    string        // optional override
	Timeout    time.Duration // default 10s

	// dYdX-only fields
	EthereumAddress          string
	StarkPublicKey           string
	StarkPrivateKey          string
	StarkPublicKeyYCoordinate string
}

type PlaceOrderRequest struct {
	Symbol        string      // required
	Market        MarketType  // optional: spot/derivatives
	Leverage      string      // optional
	Side          OrderSide    // BUY/SELL
	Type          OrderType    // LIMIT/MARKET
	Quantity      string      // required
	Price         string      // required for LIMIT
	TimeInForce   TimeInForce // GTC/IOC/FOK (LIMIT only)
	ClientOrderID string      // optional
	ReduceOnly    bool        // derivatives only
}

type Order struct {
	ID        string
	Symbol    string
	Market    MarketType
	Side      OrderSide
	Type      OrderType
	Status    OrderStatus
	Quantity  string
	Filled    string
	Price     string
	AvgPrice  string
	CreatedAt time.Time
	UpdatedAt time.Time
}

type Balance struct {
	Asset  string
	Free   string
	Locked string
	Total  string
}

type Candle struct {
	Symbol    string
	Interval  CandleInterval
	OpenTime  time.Time
	CloseTime time.Time
	Open      string
	High      string
	Low       string
	Close     string
	Volume    string
	Trades    string
}
Methods
  • Name() ExchangeName
    Returns the exchange identifier.
  • Capabilities() Capabilities
    Describes spot/derivatives/streaming support.
  • SubscribeCandles(ctx, symbol, interval)
    Returns two channels. Candles are delivered via polling. The error channel is buffered and may report intermittent issues.
  • GetCandles(ctx, symbol, interval, start, end)
    Loads historical candles in the given time range (inclusive bounds are exchange-dependent).
  • GetBalances(ctx)
    Returns unified balances for the account.
  • ListOpenOrders(ctx, symbol)
    Returns open orders. Some exchanges require a non-empty symbol.
  • ListOrders(ctx, symbol, status)
    Returns order history, optionally filtered by unified status. Pass status == "" to disable filtering.
  • PlaceOrder(ctx, req)
    Places a new order and returns the unified Order.
  • CancelOrder(ctx, symbol, orderID)
    Cancels by exchange order ID or client order ID (Binance).
  • GetOrder(ctx, symbol, orderID)
    Returns a single order by ID.
  • Ping(ctx)
    Health check.
  • ServerTime(ctx)
    Returns exchange server time.

Examples

Balances
balances, err := ex.GetBalances(ctx)
if err != nil {
	panic(err)
}
for _, b := range balances {
	fmt.Printf("%s free=%s locked=%s total=%s\n", b.Asset, b.Free, b.Locked, b.Total)
}
Place a limit order
order, err := ex.PlaceOrder(ctx, broker.PlaceOrderRequest{
	Symbol:      "BTCUSDT",
	Side:        broker.OrderSideBuy,
	Type:        broker.OrderTypeLimit,
	Quantity:    "0.001",
	Price:       "25000",
	TimeInForce: broker.TimeInForceGTC,
})
if err != nil {
	panic(err)
}
fmt.Println("order id:", order.ID)
Order history
orders, err := ex.ListOrders(ctx, "BTCUSDT", broker.OrderStatusFilled)
if err != nil {
	panic(err)
}
fmt.Println("filled orders:", len(orders))
Cancel and get order
if err := ex.CancelOrder(ctx, "BTCUSDT", "123456"); err != nil {
	panic(err)
}

order, err := ex.GetOrder(ctx, "BTCUSDT", "123456")
if err != nil {
	panic(err)
}
fmt.Println("status:", order.Status)
Candles (polling subscription)
candles, errs := ex.SubscribeCandles(ctx, "BTCUSDT", broker.CandleIntervalMinute)
for {
	select {
	case c := <-candles:
		fmt.Printf("kline %s %s o=%s c=%s\n", c.Symbol, c.Interval, c.Open, c.Close)
	case err := <-errs:
		fmt.Println("candle error:", err)
	}
}
Candles (historical)
end := time.Now()
start := end.Add(-6 * time.Hour)
items, err := ex.GetCandles(ctx, "BTCUSDT", broker.CandleIntervalMinute, start, end)
if err != nil {
	panic(err)
}
fmt.Println("candles:", len(items))

Errors

Common errors are exposed for uniform handling:

  • ErrNotSupported
  • ErrOrderNotFound
  • ErrAuth
  • ErrRateLimited
  • ErrInsufficientBalance
  • ErrInvalidConfig

The adapters map SDK errors to these where possible.

Candle intervals

Available enum values:

  • CandleIntervalTick (trade ticks from recent trades)
  • CandleIntervalSecond (1s candles from aggregated trades)
  • CandleIntervalMinute
  • CandleIntervalHour
  • CandleIntervalDay

Notes and limitations

  • Symbol format must match the target exchange (e.g. BTCUSDT for Binance/Bybit, BTC-USD for dYdX).
  • SubscribeCandles uses REST polling under the hood (no websocket stream).
  • Tick and 1s candles are derived from recent trades and may be incomplete for large historical ranges.
  • ListOrders, GetOrder, and CancelOrder return ErrInvalidConfig if symbol is empty.
  • ListOrders, GetOrder, and CancelOrder require a non-empty symbol across all adapters.
  • dYdX balances are returned as a single USDC-like asset derived from account equity/collateral.

Tests

Run unit tests:

go test ./...

Live smoke tests (requires env vars, see contract_test.go):

BROKER_LIVE_TESTS=1 go test ./...

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNotSupported        = errors.New("broker: not supported")
	ErrOrderNotFound       = errors.New("broker: order not found")
	ErrAuth                = errors.New("broker: auth failed")
	ErrRateLimited         = errors.New("broker: rate limited")
	ErrInsufficientBalance = errors.New("broker: insufficient balance")
	ErrInvalidConfig       = errors.New("broker: invalid config")
)

Functions

This section is empty.

Types

type Balance

type Balance struct {
	Asset  string
	Free   string
	Locked string
	Total  string
}

type Candle

type Candle struct {
	Symbol    string
	Interval  CandleInterval
	OpenTime  time.Time
	CloseTime time.Time
	Open      string
	High      string
	Low       string
	Close     string
	Volume    string
	Trades    string
}

type CandleInterval

type CandleInterval string
const (
	CandleIntervalTick   CandleInterval = "tick"
	CandleIntervalSecond CandleInterval = "1s"
	CandleIntervalMinute CandleInterval = "1m"
	CandleIntervalHour   CandleInterval = "1h"
	CandleIntervalDay    CandleInterval = "1d"
)

type Capabilities

type Capabilities struct {
	Spot        bool
	Derivatives bool
	Streaming   bool
}

type Config

type Config struct {
	Exchange   ExchangeName
	APIKey     string
	APISecret  string
	Passphrase string
	BaseURL    string
	Timeout    time.Duration
	// dYdX-specific credentials
	EthereumAddress           string
	StarkPublicKey            string
	StarkPrivateKey           string
	StarkPublicKeyYCoordinate string
}

type Exchange

type Exchange interface {
	Name() ExchangeName
	Capabilities() Capabilities

	SubscribeCandles(ctx context.Context, symbol string, interval CandleInterval) (<-chan Candle, <-chan error)
	GetCandles(ctx context.Context, symbol string, interval CandleInterval, start, end time.Time) ([]Candle, error)

	GetBalances(ctx context.Context) ([]Balance, error)
	ListOpenOrders(ctx context.Context, symbol string) ([]Order, error)
	ListOrders(ctx context.Context, symbol string, status OrderStatus) ([]Order, error)
	GetFeeRates(ctx context.Context, symbol string, market MarketType) (FeeRates, error)
	PlaceOrder(ctx context.Context, req PlaceOrderRequest) (Order, error)
	CancelOrder(ctx context.Context, symbol, orderID string) error
	GetOrder(ctx context.Context, symbol, orderID string) (Order, error)

	Ping(ctx context.Context) error
	ServerTime(ctx context.Context) (time.Time, error)
}

func NewExchange

func NewExchange(ctx context.Context, cfg Config) (Exchange, error)

type ExchangeName

type ExchangeName string
const (
	ExchangeBinance ExchangeName = "Binance"
	ExchangeBybit   ExchangeName = "Bybit"
	ExchangeDydx    ExchangeName = "Dydx"
)

type Facade

type Facade struct {
	Exchange
}

func New

func New(ctx context.Context, cfg Config) (*Facade, error)

type FeeRates added in v0.1.5

type FeeRates struct {
	Maker string
	Taker string
}

type MarketType added in v0.1.5

type MarketType string
const (
	MarketSpot        MarketType = "spot"
	MarketDerivatives MarketType = "derivatives"
)

type Order

type Order struct {
	ID             string
	Symbol         string
	Market         MarketType
	Side           OrderSide
	Type           OrderType
	Status         OrderStatus
	Quantity       string
	Filled         string
	Price          string
	AvgPrice       string
	CumExecFee     string
	ReduceOnly     bool
	CloseOnTrigger bool
	CreatedAt      time.Time
	UpdatedAt      time.Time
}

type OrderSide

type OrderSide string
const (
	OrderSideBuy  OrderSide = "BUY"
	OrderSideSell OrderSide = "SELL"
)

type OrderStatus

type OrderStatus string
const (
	OrderStatusNew             OrderStatus = "NEW"
	OrderStatusPartiallyFilled OrderStatus = "PARTIALLY_FILLED"
	OrderStatusFilled          OrderStatus = "FILLED"
	OrderStatusCanceled        OrderStatus = "CANCELED"
	OrderStatusRejected        OrderStatus = "REJECTED"
	OrderStatusUnknown         OrderStatus = "UNKNOWN"
)

type OrderType

type OrderType string
const (
	OrderTypeLimit  OrderType = "LIMIT"
	OrderTypeMarket OrderType = "MARKET"
)

type PlaceOrderRequest

type PlaceOrderRequest struct {
	Symbol        string
	Market        MarketType
	Leverage      string
	Side          OrderSide
	Type          OrderType
	Quantity      string
	Price         string
	TimeInForce   TimeInForce
	ClientOrderID string
	ReduceOnly    bool
	PositionIdx   string
}

type TimeInForce

type TimeInForce string
const (
	TimeInForceGTC TimeInForce = "GTC"
	TimeInForceIOC TimeInForce = "IOC"
	TimeInForceFOK TimeInForce = "FOK"
)

Jump to

Keyboard shortcuts

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