mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
* adds open interest to exchanges * ADDS TESTING YEAH * New endpoints, BTSE, RPCS, cached * slight design change, begin gateio You will need to get cached for each exchange that supports it * gateio, huobi, rpc * fix up kraken, cache retrieval * okx, gateio * finalising all implementations and tests * definitely my final ever commit on this * Well, well, well * final v2 * quick fix of bug * test coverage, assert notempty, test helper Added a new testhelper for currency management because its very annoying in a parallel test setting which wastes so much space otherwise * minimises REST requests for Open Interest * types.Number merge misses * Minimises Kraken REST calls * len change, value -> pointer receiver * further fixup * fixes gateio, batch calculates open interest * single gateio, lint const fixes * rejig and more thorough oi for huobi * formatting expansion * minor fix for handling expiring contracts * rm unused Binance strings * add bybit support, fix bybit issues * oopsie doopsie, dont look at my whoopsie * Fix issue, remove feature * move an irrelevant function for the pr * mini bybit upgrades * fixes cli request bug
366 lines
12 KiB
Go
366 lines
12 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"
|
|
|
|
// Authenticated 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(ctx context.Context) (ChainAnalysisBlock, error) {
|
|
var resp ChainAnalysisBlock
|
|
return resp, b.SendHTTPRequest(ctx, exchange.ChainAnalysis, latestBlock, &resp)
|
|
}
|
|
|
|
// GetBlockCA returns block information by blockhash from bitflyer chain
|
|
// analysis system
|
|
func (b *Bitflyer) GetBlockCA(ctx context.Context, blockhash string) (ChainAnalysisBlock, error) {
|
|
var resp ChainAnalysisBlock
|
|
return resp, b.SendHTTPRequest(ctx, exchange.ChainAnalysis, blockByBlockHash+blockhash, &resp)
|
|
}
|
|
|
|
// GetBlockbyHeightCA returns the block information by height from bitflyer chain
|
|
// analysis system
|
|
func (b *Bitflyer) GetBlockbyHeightCA(ctx context.Context, height int64) (ChainAnalysisBlock, error) {
|
|
var resp ChainAnalysisBlock
|
|
return resp, b.SendHTTPRequest(ctx, exchange.ChainAnalysis, blockByBlockHeight+strconv.FormatInt(height, 10), &resp)
|
|
}
|
|
|
|
// GetTransactionByHashCA returns transaction information by txHash from
|
|
// bitflyer chain analysis system
|
|
func (b *Bitflyer) GetTransactionByHashCA(ctx context.Context, txHash string) (ChainAnalysisTransaction, error) {
|
|
var resp ChainAnalysisTransaction
|
|
return resp, b.SendHTTPRequest(ctx, exchange.ChainAnalysis, transaction+txHash, &resp)
|
|
}
|
|
|
|
// GetAddressInfoCA returns balance information for address by addressln string
|
|
// from bitflyer chain analysis system
|
|
func (b *Bitflyer) GetAddressInfoCA(ctx context.Context, addressln string) (ChainAnalysisAddress, error) {
|
|
var resp ChainAnalysisAddress
|
|
return resp, b.SendHTTPRequest(ctx, exchange.ChainAnalysis, address+addressln, &resp)
|
|
}
|
|
|
|
// GetMarkets returns market information
|
|
func (b *Bitflyer) GetMarkets(ctx context.Context) ([]MarketInfo, error) {
|
|
var resp []MarketInfo
|
|
return resp, b.SendHTTPRequest(ctx, exchange.RestSpot, pubGetMarkets, &resp)
|
|
}
|
|
|
|
// GetOrderBook returns market orderbook depth
|
|
func (b *Bitflyer) GetOrderBook(ctx context.Context, symbol string) (Orderbook, error) {
|
|
var resp Orderbook
|
|
v := url.Values{}
|
|
v.Set("product_code", symbol)
|
|
|
|
return resp, b.SendHTTPRequest(ctx, exchange.RestSpot, pubGetBoard+"?"+v.Encode(), &resp)
|
|
}
|
|
|
|
// GetTicker returns ticker information
|
|
func (b *Bitflyer) GetTicker(ctx context.Context, symbol string) (Ticker, error) {
|
|
var resp Ticker
|
|
v := url.Values{}
|
|
v.Set("product_code", symbol)
|
|
return resp, b.SendHTTPRequest(ctx, exchange.RestSpot, pubGetTicker+"?"+v.Encode(), &resp)
|
|
}
|
|
|
|
// GetExecutionHistory returns past trades that were executed on the market
|
|
func (b *Bitflyer) GetExecutionHistory(ctx context.Context, symbol string) ([]ExecutedTrade, error) {
|
|
var resp []ExecutedTrade
|
|
v := url.Values{}
|
|
v.Set("product_code", symbol)
|
|
|
|
return resp, b.SendHTTPRequest(ctx, exchange.RestSpot, pubGetExecutionHistory+"?"+v.Encode(), &resp)
|
|
}
|
|
|
|
// GetExchangeStatus returns exchange status information
|
|
func (b *Bitflyer) GetExchangeStatus(ctx context.Context) (string, error) {
|
|
resp := make(map[string]string)
|
|
err := b.SendHTTPRequest(ctx, 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 infinity
|
|
func (b *Bitflyer) GetChats(ctx context.Context, fromDate string) ([]ChatLog, error) {
|
|
var resp []ChatLog
|
|
v := url.Values{}
|
|
v.Set("from_date", fromDate)
|
|
return resp, b.SendHTTPRequest(ctx, 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
|
|
}
|
|
|
|
// GetOpenInterestData returns a summary of open interest
|
|
func (b *Bitflyer) GetOpenInterestData() {
|
|
// 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(ctx context.Context, 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(ctx, request.Unset, func() (*request.Item, error) {
|
|
return item, nil
|
|
}, request.UnauthenticatedRequest)
|
|
}
|
|
|
|
// 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
|
|
}
|