mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-16 23:16:48 +00:00
* Bump CI versions * Specifically set go version as 1.17.x bumps it to 1.18 * Another * Adjust AppVeyor * Part 1 of linter issues * Part 2 * Fix various linters and improvements * Part 3 * Finishing touches * Tests and EqualFold * Fix nitterinos plus bonus requester jobs bump for exchanges with large number of tests * Fix nitterinos and bump golangci-lint timeout for AppVeyor * Address nits, ensure all books are returned on err due to syncer regression * Fix the wiggins * Fix duplication * Fix nitterinos
482 lines
18 KiB
Go
482 lines
18 KiB
Go
package bittrex
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/thrasher-corp/gocryptotrader/common"
|
|
"github.com/thrasher-corp/gocryptotrader/common/crypto"
|
|
"github.com/thrasher-corp/gocryptotrader/currency"
|
|
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
|
|
)
|
|
|
|
// Bittrex is the overaching type across the bittrex methods
|
|
type Bittrex struct {
|
|
exchange.Base
|
|
WsSequenceOrders int64
|
|
|
|
obm *orderbookManager
|
|
tickerCache *TickerCache
|
|
}
|
|
|
|
const (
|
|
bittrexAPIRestURL = "https://api.bittrex.com/v3"
|
|
bittrexAPIDeprecatedURL = "https://bittrex.com/api/v1.1"
|
|
|
|
// Public endpoints
|
|
getMarkets = "/markets"
|
|
getMarketSummaries = "/markets/summaries"
|
|
getTicker = "/markets/%s/ticker"
|
|
getMarketSummary = "/markets/%s/summary"
|
|
getMarketTrades = "/markets/%s/trades"
|
|
getOrderbook = "/markets/%s/orderbook?depth=%s"
|
|
getRecentCandles = "/markets/%s/candles/%s/%s/recent"
|
|
getHistoricalCandles = "/markets/%s/candles/%s/%s/historical/%s"
|
|
getCurrencies = "/currencies"
|
|
|
|
// Authenticated endpoints
|
|
getBalances = "/balances"
|
|
getBalance = "/balances/%s"
|
|
getDepositAddress = "/addresses/%s"
|
|
depositAddresses = "/addresses/"
|
|
getAllOpenOrders = "/orders/open"
|
|
getOpenOrders = "/orders/open?marketSymbol=%s"
|
|
getOrder = "/orders/%s"
|
|
getClosedOrders = "/orders/closed?marketSymbol=%s"
|
|
cancelOrder = "/orders/%s"
|
|
cancelOpenOrders = "/orders/open"
|
|
getClosedWithdrawals = "/withdrawals/closed"
|
|
getOpenWithdrawals = "/withdrawals/open"
|
|
submitWithdrawal = "/transfers"
|
|
getClosedDeposits = "/deposits/closed"
|
|
getOpenDeposits = "/deposits/open"
|
|
submitOrder = "/orders"
|
|
|
|
// Other Consts
|
|
ratePeriod = time.Minute
|
|
rateLimit = 60
|
|
orderbookDepth = 500 // ws uses REST snapshots and needs identical depths
|
|
)
|
|
|
|
// GetMarkets is used to get the open and available trading markets at Bittrex
|
|
// along with other meta data.
|
|
func (b *Bittrex) GetMarkets(ctx context.Context) ([]MarketData, error) {
|
|
var resp []MarketData
|
|
return resp, b.SendHTTPRequest(ctx, exchange.RestSpot, getMarkets, &resp, nil)
|
|
}
|
|
|
|
// GetCurrencies is used to get all supported currencies at Bittrex
|
|
func (b *Bittrex) GetCurrencies(ctx context.Context) ([]CurrencyData, error) {
|
|
var resp []CurrencyData
|
|
return resp, b.SendHTTPRequest(ctx, exchange.RestSpot, getCurrencies, &resp, nil)
|
|
}
|
|
|
|
// GetTicker sends a public get request and returns current ticker information
|
|
// on the supplied currency. Example currency input param "ltc-btc".
|
|
func (b *Bittrex) GetTicker(ctx context.Context, marketName string) (TickerData, error) {
|
|
var resp TickerData
|
|
return resp, b.SendHTTPRequest(ctx, exchange.RestSpot, fmt.Sprintf(getTicker, marketName), &resp, nil)
|
|
}
|
|
|
|
// GetMarketSummaries is used to get the last 24 hour summary of all active
|
|
// exchanges
|
|
func (b *Bittrex) GetMarketSummaries(ctx context.Context) ([]MarketSummaryData, error) {
|
|
var resp []MarketSummaryData
|
|
return resp, b.SendHTTPRequest(ctx, exchange.RestSpot, getMarketSummaries, &resp, nil)
|
|
}
|
|
|
|
// GetMarketSummary is used to get the last 24 hour summary of all active
|
|
// exchanges by currency pair (ltc-btc).
|
|
func (b *Bittrex) GetMarketSummary(ctx context.Context, marketName string) (MarketSummaryData, error) {
|
|
var resp MarketSummaryData
|
|
return resp, b.SendHTTPRequest(ctx, exchange.RestSpot, fmt.Sprintf(getMarketSummary, marketName), &resp, nil)
|
|
}
|
|
|
|
// GetOrderbook method returns current order book information by currency and depth.
|
|
// "marketSymbol" ie ltc-btc
|
|
// "depth" is either 1, 25 or 500. Server side, the depth defaults to 25.
|
|
func (b *Bittrex) GetOrderbook(ctx context.Context, marketName string, depth int64) (*OrderbookData, int64, error) {
|
|
strDepth := strconv.FormatInt(depth, 10)
|
|
|
|
var resp OrderbookData
|
|
var sequence int64
|
|
resultHeader := http.Header{}
|
|
err := b.SendHTTPRequest(ctx, exchange.RestSpot, fmt.Sprintf(getOrderbook, marketName, strDepth), &resp, &resultHeader)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
sequence, err = strconv.ParseInt(resultHeader.Get("sequence"), 10, 64)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
return &resp, sequence, nil
|
|
}
|
|
|
|
// GetMarketHistory retrieves the latest trades that have occurred for a specific market
|
|
func (b *Bittrex) GetMarketHistory(ctx context.Context, currency string) ([]TradeData, error) {
|
|
var resp []TradeData
|
|
return resp, b.SendHTTPRequest(ctx, exchange.RestSpot, fmt.Sprintf(getMarketTrades, currency), &resp, nil)
|
|
}
|
|
|
|
// Order places an order
|
|
func (b *Bittrex) Order(ctx context.Context, marketName, side, orderType string, timeInForce TimeInForce, price, amount, ceiling float64) (OrderData, error) {
|
|
req := make(map[string]interface{})
|
|
req["marketSymbol"] = marketName
|
|
req["direction"] = side
|
|
req["type"] = orderType
|
|
req["quantity"] = strconv.FormatFloat(amount, 'f', -1, 64)
|
|
if orderType == "CEILING_LIMIT" || orderType == "CEILING_MARKET" {
|
|
req["ceiling"] = strconv.FormatFloat(ceiling, 'f', -1, 64)
|
|
}
|
|
if orderType == "LIMIT" {
|
|
req["limit"] = strconv.FormatFloat(price, 'f', -1, 64)
|
|
}
|
|
if timeInForce != "" {
|
|
req["timeInForce"] = timeInForce
|
|
} else {
|
|
req["timeInForce"] = GoodTilCancelled
|
|
}
|
|
var resp OrderData
|
|
return resp, b.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, submitOrder, nil, req, &resp, nil)
|
|
}
|
|
|
|
// GetOpenOrders returns all orders that you currently have opened.
|
|
// A specific market can be requested for example "ltc-btc"
|
|
func (b *Bittrex) GetOpenOrders(ctx context.Context, marketName string) ([]OrderData, int64, error) {
|
|
var path string
|
|
if marketName == "" || marketName == " " {
|
|
path = getAllOpenOrders
|
|
} else {
|
|
path = fmt.Sprintf(getOpenOrders, marketName)
|
|
}
|
|
var resp []OrderData
|
|
var sequence int64
|
|
resultHeader := http.Header{}
|
|
err := b.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, path, nil, nil, &resp, &resultHeader)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
sequence, err = strconv.ParseInt(resultHeader.Get("sequence"), 10, 64)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
return resp, sequence, err
|
|
}
|
|
|
|
// CancelExistingOrder is used to cancel a buy or sell order.
|
|
func (b *Bittrex) CancelExistingOrder(ctx context.Context, uuid string) (OrderData, error) {
|
|
var resp OrderData
|
|
return resp, b.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodDelete, fmt.Sprintf(cancelOrder, uuid), nil, nil, &resp, nil)
|
|
}
|
|
|
|
// CancelOpenOrders is used to cancel all open orders for a specific market
|
|
// Or cancel all orders for all markets if the parameter `markets` is set to ""
|
|
func (b *Bittrex) CancelOpenOrders(ctx context.Context, market string) ([]BulkCancelResultData, error) {
|
|
var resp []BulkCancelResultData
|
|
|
|
params := url.Values{}
|
|
if market != "" {
|
|
params.Set("marketSymbol", market)
|
|
}
|
|
|
|
return resp, b.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodDelete, cancelOpenOrders, params, nil, &resp, nil)
|
|
}
|
|
|
|
// GetRecentCandles retrieves recent candles;
|
|
// Interval: MINUTE_1, MINUTE_5, HOUR_1, or DAY_1
|
|
// Type: TRADE or MIDPOINT
|
|
func (b *Bittrex) GetRecentCandles(ctx context.Context, marketName, candleInterval, candleType string) ([]CandleData, error) {
|
|
var resp []CandleData
|
|
|
|
return resp, b.SendHTTPRequest(ctx, exchange.RestSpot, fmt.Sprintf(getRecentCandles, marketName, candleType, candleInterval), &resp, nil)
|
|
}
|
|
|
|
// GetHistoricalCandles retrieves recent candles
|
|
// Type: TRADE or MIDPOINT
|
|
func (b *Bittrex) GetHistoricalCandles(ctx context.Context, marketName, candleInterval, candleType string, year, month, day int) ([]CandleData, error) {
|
|
var resp []CandleData
|
|
|
|
var start string
|
|
switch candleInterval {
|
|
case "MINUTE_1", "MINUTE_5":
|
|
// Retrieve full day
|
|
start = fmt.Sprintf("%d/%d/%d", year, month, day)
|
|
case "HOUR_1":
|
|
// Retrieve full month
|
|
start = fmt.Sprintf("%d/%d", year, month)
|
|
case "DAY_1":
|
|
// Retrieve full year
|
|
start = fmt.Sprintf("%d", year)
|
|
default:
|
|
return resp, fmt.Errorf("invalid interval %v, not supported", candleInterval)
|
|
}
|
|
|
|
return resp, b.SendHTTPRequest(ctx, exchange.RestSpot, fmt.Sprintf(getHistoricalCandles, marketName, candleType, candleInterval, start), &resp, nil)
|
|
}
|
|
|
|
// GetBalances is used to retrieve all balances from your account
|
|
func (b *Bittrex) GetBalances(ctx context.Context) ([]BalanceData, error) {
|
|
var resp []BalanceData
|
|
return resp, b.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, getBalances, nil, nil, &resp, nil)
|
|
}
|
|
|
|
// GetAccountBalanceByCurrency is used to retrieve the balance from your account
|
|
// for a specific currency. ie. "btc" or "ltc"
|
|
func (b *Bittrex) GetAccountBalanceByCurrency(ctx context.Context, currency string) (BalanceData, error) {
|
|
var resp BalanceData
|
|
return resp, b.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, fmt.Sprintf(getBalance, currency), nil, nil, &resp, nil)
|
|
}
|
|
|
|
// GetCryptoDepositAddresses is used to retrieve all deposit addresses
|
|
func (b *Bittrex) GetCryptoDepositAddresses(ctx context.Context) ([]AddressData, error) {
|
|
var resp []AddressData
|
|
return resp, b.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, depositAddresses, nil, nil, &resp, nil)
|
|
}
|
|
|
|
// GetCryptoDepositAddress is used to retrieve an address for a specific currency
|
|
func (b *Bittrex) GetCryptoDepositAddress(ctx context.Context, currency string) (AddressData, error) {
|
|
var resp AddressData
|
|
return resp, b.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, fmt.Sprintf(getDepositAddress, currency), nil, nil, &resp, nil)
|
|
}
|
|
|
|
// ProvisionNewDepositAddress provisions a new deposit address for a specific currency
|
|
func (b *Bittrex) ProvisionNewDepositAddress(ctx context.Context, currency string) (*ProvisionNewAddressData, error) {
|
|
req := make(map[string]interface{}, 1)
|
|
req["currencySymbol"] = currency
|
|
var resp ProvisionNewAddressData
|
|
return &resp, b.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, depositAddresses, nil, req, &resp, nil)
|
|
}
|
|
|
|
// Withdraw is used to withdraw funds from your account.
|
|
func (b *Bittrex) Withdraw(ctx context.Context, currency, paymentID, address string, quantity float64) (WithdrawalData, error) {
|
|
req := make(map[string]interface{})
|
|
req["currencySymbol"] = currency
|
|
req["quantity"] = strconv.FormatFloat(quantity, 'f', -1, 64)
|
|
req["cryptoAddress"] = address
|
|
if len(paymentID) > 0 {
|
|
req["cryptoAddressTag"] = paymentID
|
|
}
|
|
var resp WithdrawalData
|
|
return resp, b.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodPost, submitWithdrawal, nil, req, &resp, nil)
|
|
}
|
|
|
|
// GetOrder is used to retrieve a single order by UUID.
|
|
func (b *Bittrex) GetOrder(ctx context.Context, uuid string) (OrderData, error) {
|
|
var resp OrderData
|
|
return resp, b.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, fmt.Sprintf(getOrder, uuid), nil, nil, &resp, nil)
|
|
}
|
|
|
|
// GetOrderHistoryForCurrency is used to retrieve your order history. If marketName
|
|
// is omitted it will return the entire order History.
|
|
func (b *Bittrex) GetOrderHistoryForCurrency(ctx context.Context, currency string) ([]OrderData, error) {
|
|
var resp []OrderData
|
|
return resp, b.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, fmt.Sprintf(getClosedOrders, currency), nil, nil, &resp, nil)
|
|
}
|
|
|
|
// GetClosedWithdrawals is used to retrieve your withdrawal history.
|
|
func (b *Bittrex) GetClosedWithdrawals(ctx context.Context) ([]WithdrawalData, error) {
|
|
var resp []WithdrawalData
|
|
|
|
return resp, b.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, getClosedWithdrawals, nil, nil, &resp, nil)
|
|
}
|
|
|
|
// GetClosedWithdrawalsForCurrency is used to retrieve your withdrawal history for the specified currency.
|
|
func (b *Bittrex) GetClosedWithdrawalsForCurrency(ctx context.Context, currency string) ([]WithdrawalData, error) {
|
|
var resp []WithdrawalData
|
|
|
|
params := url.Values{}
|
|
params.Set("currencySymbol", currency)
|
|
|
|
return resp, b.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, getClosedWithdrawals, params, nil, &resp, nil)
|
|
}
|
|
|
|
// GetOpenWithdrawals is used to retrieve your withdrawal history. If currency
|
|
// omitted it will return the entire history
|
|
func (b *Bittrex) GetOpenWithdrawals(ctx context.Context) ([]WithdrawalData, error) {
|
|
var resp []WithdrawalData
|
|
return resp, b.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, getOpenWithdrawals, nil, nil, &resp, nil)
|
|
}
|
|
|
|
// GetClosedDeposits is used to retrieve your deposit history.
|
|
func (b *Bittrex) GetClosedDeposits(ctx context.Context) ([]DepositData, error) {
|
|
var resp []DepositData
|
|
return resp, b.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, getClosedDeposits, nil, nil, &resp, nil)
|
|
}
|
|
|
|
// GetClosedDepositsForCurrency is used to retrieve your deposit history for the specified currency
|
|
func (b *Bittrex) GetClosedDepositsForCurrency(ctx context.Context, currency string) ([]DepositData, error) {
|
|
var resp []DepositData
|
|
|
|
params := url.Values{}
|
|
params.Set("currencySymbol", currency)
|
|
|
|
return resp, b.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, getClosedDeposits, params, nil, &resp, nil)
|
|
}
|
|
|
|
// GetClosedDepositsPaginated is used to retrieve your deposit history.
|
|
// The maximum page size is 200 and it defaults to 100.
|
|
// PreviousPageToken is the unique identifier of the item that the resulting
|
|
// query result should end before, in the sort order of the given endpoint. Used
|
|
// for traversing a paginated set in the reverse direction.
|
|
func (b *Bittrex) GetClosedDepositsPaginated(ctx context.Context, pageSize int, previousPageTokenOptional ...string) ([]DepositData, error) {
|
|
var resp []DepositData
|
|
|
|
params := url.Values{}
|
|
params.Set("pageSize", strconv.Itoa(pageSize))
|
|
|
|
if len(previousPageTokenOptional) > 0 {
|
|
params.Set("previousPageToken", previousPageTokenOptional[0])
|
|
}
|
|
|
|
return resp, b.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, getClosedDeposits, params, nil, &resp, nil)
|
|
}
|
|
|
|
// GetOpenDeposits is used to retrieve your open deposits.
|
|
func (b *Bittrex) GetOpenDeposits(ctx context.Context) ([]DepositData, error) {
|
|
var resp []DepositData
|
|
return resp, b.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, getOpenDeposits, nil, nil, &resp, nil)
|
|
}
|
|
|
|
// GetOpenDepositsForCurrency is used to retrieve your open deposits for the specified currency
|
|
func (b *Bittrex) GetOpenDepositsForCurrency(ctx context.Context, currency string) ([]DepositData, error) {
|
|
var resp []DepositData
|
|
|
|
params := url.Values{}
|
|
params.Set("currencySymbol", currency)
|
|
|
|
return resp, b.SendAuthHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, getOpenDeposits, params, nil, &resp, nil)
|
|
}
|
|
|
|
// SendHTTPRequest sends an unauthenticated HTTP request
|
|
func (b *Bittrex) SendHTTPRequest(ctx context.Context, ep exchange.URL, path string, result interface{}, resultHeader *http.Header) error {
|
|
endpoint, err := b.API.Endpoints.GetURL(ep)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
item := &request.Item{
|
|
Method: http.MethodGet,
|
|
Path: endpoint + path,
|
|
Result: result,
|
|
Verbose: b.Verbose,
|
|
HTTPDebugging: b.HTTPDebugging,
|
|
HTTPRecording: b.HTTPRecording,
|
|
HeaderResponse: resultHeader,
|
|
}
|
|
return b.SendPayload(ctx, request.Unset, func() (*request.Item, error) { return item, nil })
|
|
}
|
|
|
|
// SendAuthHTTPRequest sends an authenticated request
|
|
func (b *Bittrex) SendAuthHTTPRequest(ctx context.Context, ep exchange.URL, method, action string, params url.Values, data, result interface{}, resultHeader *http.Header) error {
|
|
creds, err := b.GetCredentials(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
endpoint, err := b.API.Endpoints.GetURL(ep)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
newRequest := func() (*request.Item, error) {
|
|
ts := strconv.FormatInt(time.Now().UnixMilli(), 10)
|
|
path := common.EncodeURLValues(action, params)
|
|
|
|
var body io.Reader
|
|
var hmac, payload []byte
|
|
var contentHash string
|
|
if data == nil {
|
|
payload = []byte("")
|
|
} else {
|
|
var err error
|
|
payload, err = json.Marshal(data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
body = bytes.NewBuffer(payload)
|
|
hash, err := crypto.GetSHA512(payload)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
contentHash = crypto.HexEncodeToString(hash)
|
|
sigPayload := ts + endpoint + path + method + contentHash
|
|
hmac, err = crypto.GetHMAC(crypto.HashSHA512,
|
|
[]byte(sigPayload),
|
|
[]byte(creds.Secret))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
headers := make(map[string]string)
|
|
headers["Api-Key"] = creds.Key
|
|
headers["Api-Timestamp"] = ts
|
|
headers["Api-Content-Hash"] = contentHash
|
|
headers["Api-Signature"] = crypto.HexEncodeToString(hmac)
|
|
headers["Content-Type"] = "application/json"
|
|
headers["Accept"] = "application/json"
|
|
|
|
return &request.Item{
|
|
Method: method,
|
|
Path: endpoint + path,
|
|
Headers: headers,
|
|
Body: body,
|
|
Result: result,
|
|
AuthRequest: true,
|
|
Verbose: b.Verbose,
|
|
HTTPDebugging: b.HTTPDebugging,
|
|
HTTPRecording: b.HTTPRecording,
|
|
HeaderResponse: resultHeader,
|
|
}, nil
|
|
}
|
|
|
|
return b.SendPayload(ctx, request.Unset, newRequest)
|
|
}
|
|
|
|
// GetFee returns an estimate of fee based on type of transaction
|
|
func (b *Bittrex) GetFee(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) {
|
|
var fee float64
|
|
var err error
|
|
|
|
switch feeBuilder.FeeType {
|
|
case exchange.CryptocurrencyTradeFee:
|
|
fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount)
|
|
case exchange.CryptocurrencyWithdrawalFee:
|
|
fee, err = b.GetWithdrawalFee(ctx, feeBuilder.Pair.Base)
|
|
case exchange.OfflineTradeFee:
|
|
fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount)
|
|
}
|
|
if fee < 0 {
|
|
fee = 0
|
|
}
|
|
return fee, err
|
|
}
|
|
|
|
// GetWithdrawalFee returns the fee for withdrawing from the exchange
|
|
func (b *Bittrex) GetWithdrawalFee(ctx context.Context, c currency.Code) (float64, error) {
|
|
var fee float64
|
|
|
|
currencies, err := b.GetCurrencies(ctx)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
for i := range currencies {
|
|
if currencies[i].Symbol == c.String() {
|
|
fee = currencies[i].TxFee
|
|
}
|
|
}
|
|
return fee, nil
|
|
}
|
|
|
|
// calculateTradingFee returns the fee for trading any currency on Bittrex
|
|
func calculateTradingFee(price, amount float64) float64 {
|
|
return 0.0025 * price * amount
|
|
}
|