package markets import ( "fmt" "github.com/jloup/poloniex" "github.com/shopspring/decimal" ) type CurrencyPair struct { Name string Rate decimal.Decimal } type Poloniex struct { TickerCache map[string]CurrencyPair publicClient *poloniex.Poloniex updateTickerChan chan CurrencyPair } func NewPoloniex() *Poloniex { client, _ := poloniex.NewClient("", "") return &Poloniex{ TickerCache: make(map[string]CurrencyPair), updateTickerChan: nil, publicClient: client, } } func (p *Poloniex) GetBalance(apiKey, apiSecret, base_currency string) (decimal.Decimal, error) { client, _ := poloniex.NewClient(apiKey, apiSecret) accounts, err := client.TradeReturnAvailableAccountBalances() if err != nil { return decimal.Zero, err } marginBalance, err := p.computeAccountBalance(accounts.Margin, base_currency) if err != nil { return decimal.Zero, err } exchangeBalance, err := p.computeAccountBalance(accounts.Exchange, base_currency) if err != nil { return decimal.Zero, err } return decimal.Sum(marginBalance, exchangeBalance), nil } func (p *Poloniex) computeAccountBalance(account map[string]decimal.Decimal, base_currency string) (decimal.Decimal, error) { var total decimal.Decimal for currency, amount := range account { pair, err := p.GetCurrencyPair(base_currency, currency) if err != nil { return decimal.Zero, err } total = total.Add(amount.Mul(pair.Rate)) } return total, nil } func (p *Poloniex) GetCurrencyPair(curr1, curr2 string) (CurrencyPair, error) { pairName := fmt.Sprintf("%s_%s", curr1, curr2) fmt.Println(pairName) if curr1 == curr2 { return CurrencyPair{pairName, decimal.NewFromFloat(1.0)}, nil } pair, ok := p.TickerCache[pairName] if !ok { pair, err := p.fetchTicker(pairName) if err != nil { return CurrencyPair{}, err } return pair, nil } return pair, nil } func (p *Poloniex) fetchTicker(pair string) (CurrencyPair, error) { tickers, err := p.publicClient.PubReturnTickers() if err != nil { return CurrencyPair{}, err } if ticker, ok := tickers[pair]; ok { pair := CurrencyPair{Name: pair, Rate: ticker.Last} if p.updateTickerChan != nil { p.updateTickerChan <- pair } return pair, nil } else { return CurrencyPair{}, fmt.Errorf("pair '%v' not in tickers", pair) } } func (p *Poloniex) StartTicker() error { stream, err := poloniex.NewWSClient() if err != nil { return err } err = stream.SubscribeTicker() if err != nil { return err } p.updateTickerChan = make(chan CurrencyPair) go func() { for { quit := false select { case data, ok := <-stream.Subs["ticker"]: if !ok { quit = true } else { ticker := data.(poloniex.WSTicker) p.TickerCache[ticker.CurrencyPair] = CurrencyPair{Name: ticker.CurrencyPair, Rate: decimal.NewFromFloat(ticker.Last)} } case pair, ok := <-p.updateTickerChan: if !ok { quit = true } else { p.TickerCache[pair.Name] = pair } } if quit { //TODO: logit p.updateTickerChan = nil break } } }() return nil }