Files
gocryptotrader/exchanges/bitflyer/bitflyer.go
Ryan O'Hara-Reid 279b53827f requester: defer execution of request.Item generation in closure (#723)
* requester: defer execution of request.Item generation in closure.

* bithumb: fix issue

* coinut/itbit: fix linter issues

* binance: fix bug on recvWindow setting

* requester: standardize sendpayload + add readme update

* nonce: remove inc() function

* request: defer unlockiflocked

* binance: revert changes for open orders

* btcmarkets: defer auth generation functionality, rm context deadline as this will be created just before sending HTTP request.

* binance: move const to top

* exmo: remove debug output as its generated in the requester function

* ftx: defer auth functionality

* requester: move error to top

* bittrex: defer auth functionality

* bitmex: defer auth functionality and remove deadline as generation occurs after rate limiting.

* btse: defer auth functionality

* coinbasepro: defer auth functionality and removed context deadline as this is generated after rate limiting

* coinbene: defer auth functionality and remove context deadline as this is generated after rate limiting

* huobi: defer auth functionality and remove context deadline as this is generated after rate limiting

* huobi-futures: defer auth functionality and remove context deadline as this is generated after rate limiting

* kraken: defer auth functionality and remove context deadline as this is generated after rate limiting

* kraken: remove deadline protection for timestamp generation

* okgroup: defer auth functionality and remove context deadline as this is generated after rate limiting

* poloniex: defer auth functionality

* zb: defer auth functionality and remove context deadline as this is generated after rate limiting

* exchanges: clean up log output which are done and inspected in the requester package

* binance: fix path bug on every retry, rm timeout context as this is not needed

* coinbene: fix path bug on retry

* binance: consolidate functionality

* coinbene: fix linter issues

* poloniex: linter fix

* kraken: change add -> set

* bitstamp: fix path bug for retry

* BTSE: fix retry path bug

* coinbene: fix path bug whoopsie by me

* gateio: fix bug where on retry it does not reset reader

* localbitcoins: fix path bug on retry

* zb: change domain to land

* exchanges: make sure io.Reader is generated every request

* exchanges: move reader generation into function scope

* wrapper_issues: setup exchange manager

* engine: expand withdraw manager test

* engine: dont look for environment

* bitstamp: fix pathing bug (@thrasher-)

* engine/withdraw_manager: purge tests as this is covered in repository withdraw
2021-08-06 17:24:38 +10:00

366 lines
11 KiB
Go

package bitflyer
import (
"context"
"errors"
"net/http"
"net/url"
"strconv"
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
)
const (
// Bitflyer chain analysis endpoints
// APIURL
chainAnalysis = "https://chainflyer.bitflyer.jp/v1/"
// Public endpoints for chain analysis
latestBlock = "block/latest"
blockByBlockHash = "block/"
blockByBlockHeight = "block/height/"
transaction = "tx/"
address = "address/"
// APIURL
japanURL = "https://api.bitflyer.jp/v1"
usURL = "https://api.bitflyer.com/v1"
europeURL = "https://api.bitflyer.com/v1"
// Public Endpoints
pubGetMarkets = "/getmarkets/"
pubGetBoard = "/getboard"
pubGetTicker = "/getticker"
pubGetExecutionHistory = "/getexecutions"
pubGetHealth = "/gethealth"
pubGetChats = "/getchats"
// Autheticated Endpoints
privGetPermissions = "/me/getpermissions"
privGetBalance = "/me/getbalance"
privMarginStatus = "/me/getcollateral"
privGetCollateralAcc = "/me/getcollateralaccounts"
privGetDepositAddress = "/me/getaddresses"
privDepositHistory = "/me/getcoinins"
privTransactionHistory = "/me/getcoinouts"
privBankAccSummary = "/me/getbankaccounts"
privGetDeposits = "/me/getdeposits"
privWithdraw = "/me/withdraw"
privDepositCancellationHistory = "/me/getwithdrawals"
privSendOrder = "/me/sendchildorder"
privCancelOrder = "/me/cancelchildorder"
privParentOrder = "/me/sendparentorder"
privCancelParentOrder = "/me/cancelparentorder"
privCancelOrders = "/me/cancelallchildorders"
privListOrders = "/me/getchildorders"
privListParentOrders = "/me/getparentorders"
privParentOrderDetails = "/me/getparentorder"
privExecutions = "/me/getexecutions"
privOpenInterest = "/me/getpositions"
privMarginChange = "/me/getcollateralhistory"
privTradingCommission = "/me/gettradingcommission"
orders request.EndpointLimit = iota
lowVolume
)
// Bitflyer is the overarching type across this package
type Bitflyer struct {
exchange.Base
}
// GetLatestBlockCA returns the latest block information from bitflyer chain
// analysis system
func (b *Bitflyer) GetLatestBlockCA() (ChainAnalysisBlock, error) {
var resp ChainAnalysisBlock
return resp, b.SendHTTPRequest(exchange.ChainAnalysis, latestBlock, &resp)
}
// GetBlockCA returns block information by blockhash from bitflyer chain
// analysis system
func (b *Bitflyer) GetBlockCA(blockhash string) (ChainAnalysisBlock, error) {
var resp ChainAnalysisBlock
return resp, b.SendHTTPRequest(exchange.ChainAnalysis, blockByBlockHash+blockhash, &resp)
}
// GetBlockbyHeightCA returns the block information by height from bitflyer chain
// analysis system
func (b *Bitflyer) GetBlockbyHeightCA(height int64) (ChainAnalysisBlock, error) {
var resp ChainAnalysisBlock
return resp, b.SendHTTPRequest(exchange.ChainAnalysis, blockByBlockHeight+strconv.FormatInt(height, 10), &resp)
}
// GetTransactionByHashCA returns transaction information by txHash from
// bitflyer chain analysis system
func (b *Bitflyer) GetTransactionByHashCA(txHash string) (ChainAnalysisTransaction, error) {
var resp ChainAnalysisTransaction
return resp, b.SendHTTPRequest(exchange.ChainAnalysis, transaction+txHash, &resp)
}
// GetAddressInfoCA returns balance information for address by addressln string
// from bitflyer chain analysis system
func (b *Bitflyer) GetAddressInfoCA(addressln string) (ChainAnalysisAddress, error) {
var resp ChainAnalysisAddress
return resp, b.SendHTTPRequest(exchange.ChainAnalysis, address+addressln, &resp)
}
// GetMarkets returns market information
func (b *Bitflyer) GetMarkets() ([]MarketInfo, error) {
var resp []MarketInfo
return resp, b.SendHTTPRequest(exchange.RestSpot, pubGetMarkets, &resp)
}
// GetOrderBook returns market orderbook depth
func (b *Bitflyer) GetOrderBook(symbol string) (Orderbook, error) {
var resp Orderbook
v := url.Values{}
v.Set("product_code", symbol)
return resp, b.SendHTTPRequest(exchange.RestSpot, pubGetBoard+"?"+v.Encode(), &resp)
}
// GetTicker returns ticker information
func (b *Bitflyer) GetTicker(symbol string) (Ticker, error) {
var resp Ticker
v := url.Values{}
v.Set("product_code", symbol)
return resp, b.SendHTTPRequest(exchange.RestSpot, pubGetTicker+"?"+v.Encode(), &resp)
}
// GetExecutionHistory returns past trades that were executed on the market
func (b *Bitflyer) GetExecutionHistory(symbol string) ([]ExecutedTrade, error) {
var resp []ExecutedTrade
v := url.Values{}
v.Set("product_code", symbol)
return resp, b.SendHTTPRequest(exchange.RestSpot, pubGetExecutionHistory+"?"+v.Encode(), &resp)
}
// GetExchangeStatus returns exchange status information
func (b *Bitflyer) GetExchangeStatus() (string, error) {
resp := make(map[string]string)
err := b.SendHTTPRequest(exchange.RestSpot, pubGetHealth, &resp)
if err != nil {
return "", err
}
switch resp["status"] {
case "BUSY":
return "the exchange is experiencing high traffic", nil
case "VERY BUSY":
return "the exchange is experiencing heavy traffic", nil
case "SUPER BUSY":
return "the exchange is experiencing extremely heavy traffic. There is a possibility that orders will fail or be processed after a delay.", nil
case "STOP":
return "STOP", errors.New("the exchange has been stopped. Orders will not be accepted")
}
return "NORMAL", nil
}
// GetChats returns trollbox chat log
// Note: returns vary from instant to infinty
func (b *Bitflyer) GetChats(fromDate string) ([]ChatLog, error) {
var resp []ChatLog
v := url.Values{}
v.Set("from_date", fromDate)
return resp, b.SendHTTPRequest(exchange.RestSpot, pubGetChats+"?"+v.Encode(), &resp)
}
// GetPermissions returns current permissions for associated with your API
// keys
func (b *Bitflyer) GetPermissions() {
// Needs to be updated
}
// GetAccountBalance returnsthe full list of account funds
func (b *Bitflyer) GetAccountBalance() {
// Needs to be updated
}
// GetMarginStatus returns current margin status
func (b *Bitflyer) GetMarginStatus() {
// Needs to be updated
}
// GetCollateralAccounts returns a full list of collateralised accounts
func (b *Bitflyer) GetCollateralAccounts() {
// Needs to be updated
}
// GetCryptoDepositAddress returns an address for cryptocurrency deposits
func (b *Bitflyer) GetCryptoDepositAddress() {
// Needs to be updated
}
// GetDepositHistory returns a full history of deposits
func (b *Bitflyer) GetDepositHistory() {
// Needs to be updated
}
// GetTransactionHistory returns a full history of transactions
func (b *Bitflyer) GetTransactionHistory() {
// Needs to be updated
}
// GetBankAccSummary returns a full list of bank accounts assoc. with your keys
func (b *Bitflyer) GetBankAccSummary() {
// Needs to be updated
}
// GetCashDeposits returns a full list of cash deposits to the exchange
func (b *Bitflyer) GetCashDeposits() {
// Needs to be updated
}
// WithdrawFunds withdraws funds to a certain bank
func (b *Bitflyer) WithdrawFunds() {
// Needs to be updated
}
// GetDepositCancellationHistory returns the cancellation history of deposits
func (b *Bitflyer) GetDepositCancellationHistory() {
// Needs to be updated
}
// SendOrder creates new order
func (b *Bitflyer) SendOrder() {
// Needs to be updated
}
// CancelExistingOrder cancels an order
func (b *Bitflyer) CancelExistingOrder() {
// Needs to be updated
}
// SendParentOrder sends a special order
func (b *Bitflyer) SendParentOrder() {
// Needs to be updated
}
// CancelParentOrder cancels a special order
func (b *Bitflyer) CancelParentOrder() {
// Needs to be updated
}
// CancelAllExistingOrders cancels all orders on the exchange
func (b *Bitflyer) CancelAllExistingOrders() {
// Needs to be updated
}
// GetAllOrders returns a list of all orders
func (b *Bitflyer) GetAllOrders() {
// Needs to be updated
}
// GetParentOrders returns a list of all parent orders
func (b *Bitflyer) GetParentOrders() {
// Needs to be updated
}
// GetParentOrderDetails returns a detailing of a parent order
func (b *Bitflyer) GetParentOrderDetails() {
// Needs to be updated
}
// GetExecutions returns execution details
func (b *Bitflyer) GetExecutions() {
// Needs to be updated
}
// GetOpenInterest returns a summary of open interest
func (b *Bitflyer) GetOpenInterest() {
// Needs to be updated
}
// GetMarginChange returns collateral history
func (b *Bitflyer) GetMarginChange() {
// Needs to be updated
}
// GetTradingCommission returns trading commission
func (b *Bitflyer) GetTradingCommission() {
// Needs to be updated
}
// SendHTTPRequest sends an unauthenticated request
func (b *Bitflyer) SendHTTPRequest(ep exchange.URL, path string, result interface{}) 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,
}
return b.SendPayload(context.Background(), request.Unset, func() (*request.Item, error) {
return item, nil
})
}
// SendAuthHTTPRequest sends an authenticated HTTP request
// Note: HTTP not done due to incorrect account privileges, please open a PR
// if you have access and update the authenticated requests
// TODO: Fill out this function once API access is obtained
func (b *Bitflyer) SendAuthHTTPRequest() {
// nolint:gocritic // code example
// headers := make(map[string]string)
// headers["ACCESS-KEY"] = b.API.Credentials.Key
// headers["ACCESS-TIMESTAMP"] = strconv.FormatInt(time.Now().UnixNano(), 10)
}
// GetFee returns an estimate of fee based on type of transaction
// TODO: Figure out the weird fee structure. Do we use Bitcoin Easy Exchange,Lightning Spot,Bitcoin Market,Lightning FX/Futures ???
func (b *Bitflyer) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) {
var fee float64
switch feeBuilder.FeeType {
case exchange.CryptocurrencyTradeFee:
fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount)
case exchange.InternationalBankDepositFee:
fee = getDepositFee(feeBuilder.BankTransactionType, feeBuilder.FiatCurrency)
case exchange.InternationalBankWithdrawalFee:
fee = getWithdrawalFee(feeBuilder.BankTransactionType, feeBuilder.FiatCurrency, feeBuilder.Amount)
case exchange.OfflineTradeFee:
fee = calculateTradingFee(feeBuilder.PurchasePrice, feeBuilder.Amount)
}
if fee < 0 {
fee = 0
}
return fee, nil
}
// calculateTradingFee returns fee when performing a trade
func calculateTradingFee(price, amount float64) float64 {
// bitflyer has fee tiers, but does not disclose them via API, so the largest has to be assumed
return 0.0012 * price * amount
}
func getDepositFee(bankTransactionType exchange.InternationalBankTransactionType, c currency.Code) (fee float64) {
if bankTransactionType == exchange.WireTransfer {
if c.Item == currency.JPY.Item {
fee = 324
}
}
return fee
}
func getWithdrawalFee(bankTransactionType exchange.InternationalBankTransactionType, c currency.Code, amount float64) (fee float64) {
if bankTransactionType == exchange.WireTransfer {
if c.Item == currency.JPY.Item {
if amount < 30000 {
fee = 540
} else {
fee = 756
}
}
}
return fee
}