func (b *Bitfinex) GetTrades(currencyPair string, values url.Values) ([]TradeStructure, error) {
	response := []TradeStructure{}
	path := common.EncodeURLValues(
		bitfinexAPIURL+bitfinexTrades+currencyPair,
		values,
	)
	return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
}
GetTrades returns a list of the most recent trades for the given curencyPair
By default the response will return 100 trades
CurrencyPair - Example "BTCUSD"
Values can contain limit amounts for the number of trades returned - Example
"limit_trades" = 1000
package bitfinex
import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"strings"
	"time"
	"github.com/gorilla/websocket"
	"github.com/mattkanwisher/cryptofiend/common"
	"github.com/mattkanwisher/cryptofiend/config"
	"github.com/mattkanwisher/cryptofiend/currency/pair"
	"github.com/mattkanwisher/cryptofiend/exchanges"
	"github.com/mattkanwisher/cryptofiend/exchanges/orderbook"
	"github.com/mattkanwisher/cryptofiend/exchanges/ticker"
)
const (
	bitfinexAPIURL                   = "https://api.bitfinex.com/v1/"
	bitfinexAPIVersion1        uint8 = 1
	bitfinexTicker                   = "pubticker/"
	bitfinexStats                    = "stats/"
	bitfinexLendbook                 = "lendbook/"
	bitfinexOrderbook                = "book/"
	bitfinexTrades                   = "trades/"
	bitfinexKeyPermissions           = "key_info"
	bitfinexLends                    = "lends/"
	bitfinexSymbols                  = "symbols/"
	bitfinexSymbolsDetails           = "symbols_details/"
	bitfinexAccountInfo              = "account_infos"
	bitfinexAccountFees              = "account_fees"
	bitfinexAccountSummary           = "summary"
	bitfinexDeposit                  = "deposit/new"
	bitfinexOrderNew                 = "order/new"
	bitfinexOrderNewMulti            = "order/new/multi"
	bitfinexOrderCancel              = "order/cancel"
	bitfinexOrderCancelMulti         = "order/cancel/multi"
	bitfinexOrderCancelAll           = "order/cancel/all"
	bitfinexOrderCancelReplace       = "order/cancel/replace"
	bitfinexOrderStatus              = "order/status"
	bitfinexOrders                   = "orders"
	bitfinexPositions                = "positions"
	bitfinexClaimPosition            = "position/claim"
	bitfinexHistory                  = "history"
	bitfinexHistoryMovements         = "history/movements"
	bitfinexTradeHistory             = "mytrades"
	bitfinexOfferNew                 = "offer/new"
	bitfinexOfferCancel              = "offer/cancel"
	bitfinexOfferStatus              = "offer/status"
	bitfinexOffers                   = "offers"
	bitfinexMarginActiveFunds        = "taken_funds"
	bitfinexMarginTotalFunds         = "total_taken_funds"
	bitfinexMarginUnusedFunds        = "unused_taken_funds"
	bitfinexMarginClose              = "funding/close"
	bitfinexBalances                 = "balances"
	bitfinexMarginInfo               = "margin_infos"
	bitfinexTransfer                 = "transfer"
	bitfinexWithdrawal               = "withdraw"
	bitfinexActiveCredits            = "credits"
	bitfinexAPI2URL                    = "https://api.bitfinex.com/v2/"
	bitfinexAPIVersion2          uint8 = 2
	bitfinexCalcAvailableBalance       = "auth/calc/order/avail"
	bitfinexMaxRequests = 90
)
const (
	InvalidAPIKeyErrCode = 10100
	MaintenanceErrCode   = 20060  
)
var errRateLimit = errors.New("ERR_RATE_LIMIT")
type Bitfinex struct {
	exchange.Base
	WebsocketConn         *websocket.Conn
	WebsocketSubdChannels map[int]WebsocketChanInfo
	currencyPairs map[pair.CurrencyItem]*exchange.CurrencyPairInfo
	symbolDetails map[pair.CurrencyItem]*SymbolDetails
	rateLimits map[string]int64
	ipBanStartTime int64
	lastBalances     []Balance
	lastActiveOrders []Order
}
func (b *Bitfinex) SetDefaults() {
	b.Name = "Bitfinex"
	b.Enabled = false
	b.Verbose = false
	b.Websocket = false
	b.RESTPollingDelay = 10
	b.WebsocketSubdChannels = make(map[int]WebsocketChanInfo)
	b.RequestCurrencyPairFormat.Delimiter = ""
	b.RequestCurrencyPairFormat.Uppercase = true
	b.ConfigCurrencyPairFormat.Delimiter = ""
	b.ConfigCurrencyPairFormat.Uppercase = true
	b.AssetTypes = []string{ticker.Spot}
	b.Orderbooks = orderbook.Init()
	b.rateLimits = map[string]int64{}
	b.lastBalances = []Balance{}
	b.lastActiveOrders = []Order{}
}
func (b *Bitfinex) Setup(exch config.ExchangeConfig) {
	if !exch.Enabled {
		b.SetEnabled(false)
	} else {
		b.Enabled = true
		b.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
		b.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
		b.RESTPollingDelay = exch.RESTPollingDelay
		b.Verbose = exch.Verbose
		b.Websocket = exch.Websocket
		b.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
		b.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
		b.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
		err := b.SetCurrencyPairFormat()
		if err != nil {
			log.Fatal(err)
		}
		err = b.SetAssetTypes()
		if err != nil {
			log.Fatal(err)
		}
	}
}
func (b *Bitfinex) CurrencyPairToSymbol(p pair.CurrencyPair) string {
	return p.
		Display(b.RequestCurrencyPairFormat.Delimiter, b.RequestCurrencyPairFormat.Uppercase).
		String()
}
func (b *Bitfinex) SymbolToCurrencyPair(symbol string) (pair.CurrencyPair, error) {
	if len(symbol) != 6 {
		return pair.CurrencyPair{}, fmt.Errorf("symbol %s is longer than expected", symbol)
	}
	p := pair.NewCurrencyPair(symbol[0:3], symbol[3:])
	return p.FormatPair(b.RequestCurrencyPairFormat.Delimiter, b.RequestCurrencyPairFormat.Uppercase), nil
}
type currencyLimits struct {
	exchangeName string
	data map[pair.CurrencyItem]*SymbolDetails
}
func newCurrencyLimits(exchangeName string, data map[pair.CurrencyItem]*SymbolDetails) *currencyLimits {
	return &currencyLimits{exchangeName, data}
}
func (cl *currencyLimits) GetPriceDecimalPlaces(p pair.CurrencyPair) int32 {
	k := p.Display("/", false)
	if v, exists := cl.data[k]; exists {
		return int32(v.PricePrecision)
	}
	return 0
}
func (cl *currencyLimits) GetAmountDecimalPlaces(p pair.CurrencyPair) int32 {
	return 8
}
func (cl *currencyLimits) GetMinAmount(p pair.CurrencyPair) float64 {
	k := p.Display("/", false)
	if v, exists := cl.data[k]; exists {
		return v.MinimumOrderSize
	}
	return 0
}
func (cl *currencyLimits) GetMinTotal(p pair.CurrencyPair) float64 {
	return 0
}
func (b *Bitfinex) GetLimits() exchange.ILimits {
	return newCurrencyLimits(b.Name, b.symbolDetails)
}
func (b *Bitfinex) GetCurrencyPairs() map[pair.CurrencyItem]*exchange.CurrencyPairInfo {
	return b.currencyPairs
}
func (b *Bitfinex) GetTicker(symbol string, values url.Values) (Ticker, error) {
	response := Ticker{}
	path := common.EncodeURLValues(bitfinexAPIURL+bitfinexTicker+symbol, values)
	return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
}
func (b *Bitfinex) GetStats(symbol string) ([]Stat, error) {
	response := []Stat{}
	path := fmt.Sprint(bitfinexAPIURL + bitfinexStats + symbol)
	return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
}
func (b *Bitfinex) GetFundingBook(symbol string) (FundingBook, error) {
	response := FundingBook{}
	path := fmt.Sprint(bitfinexAPIURL + bitfinexLendbook + symbol)
	return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
}
func (b *Bitfinex) GetOrderbook(currencyPair string, values url.Values) (Orderbook, error) {
	response := Orderbook{}
	path := common.EncodeURLValues(
		bitfinexAPIURL+bitfinexOrderbook+currencyPair,
		values,
	)
	return response, common.SendHTTPGetRequest(path, true, b.Verbose, &response)
}