--- /dev/null
+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
+}