mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-06-09 07:26:48 +00:00
Feature: Implement funding rates, futures and coin margin (exchange API coverage) (#530)
* ALMOST THERE * more api wips * more api thingz * testing n more api wipz * more apiz * more wips * what is goin on * more wips * whip n testing * testing * testing no keys * remove log * kraken is broken ugh * still broken * fixing auth funcs + usdtm api docs * wip * api stuffs * whip * more wips * whip * more wip * api wip n testing * wip * wip * unsaved * wip n testing * wip * wip * wip * wip * wip * wip * wip * wip * wip * whip * wrapper authenticated functions * adding asset type and fixing dependencies * wip * binance auth wrapper start * wrapper functionality * wip * wip * wip * wrapper cancel functions * order submission for wrappers * wip * more error fixing and nits * websocket beginning n error fix * wip * WOW * glorious n shazzy nits * useless nits * wip * fixing things * merge stuffs * crapveyor * crapveyor rebuild * probably broke more things than he fixed * rm lns n other thangs * hope * please * stop it * done * ofcourse * rm vb * fix lbank * appveyor please * float lev * DONT ASK RYAN FOR HELP EVER * wip * wip * endpoint upgrades continued * path upgrade * NeeeNeeeNeeeNeeeNING * fix stuffs * fixing time issue * fixing broken funcs * glorious nits * shaz changes * fixing errors for fundmon * more error fixing for fundmon * test running past 30s * basic changes * THX AGAIN SHAZBERT * path system upgrade * config upgrade * unsaved stuffs * broken wip config upgrade * path system upgrade contd. * path system upgrade contd * path upgrade ready for review * testing verbose removed * linter stuffs * appveyor stuffs * appveyor stuff * fixed? * bugfix * wip * broken stuff * fix test * wierd hack fix * appveyor pls stop * error found * more useless nits * bitmex err * broken wip * broken wip path upgrade change to uint32 * changed url lookups to uint * WOW * ready4review * config fixed HOPEFULLY * config fix and glorious changes * efficient way of getting orders and open orders * binance wrapper logic fixing * testing, adding tests and fixing lot of errrrrs * merge master * appveyor stuffs * appveyor stuffs * fmt * test * octalLiteral issue fix? * octalLiteral fix? * rm vb * prnt ln to restart * adding testz * test fixzzz * READY FOR REVIEW * Actually ready now * FORMATTING * addressing shazzy n glorious nits * crapveyor * rm vb * small change * fixing err * shazbert nits * review changes * requested changes * more requested changes * noo * last nit fixes * restart appveyor * improving test cov * Update .golangci.yml * shazbert changes * moving pair formatting * format pair update wip * path upgrade complete * error fix * appveyor linters * more linters * remove testexch * more formatting changes * changes * shazbert changes * checking older requested changes to ensure completion * wip * fixing broken code * error fix * all fixed * additional changes * more changes * remove commented code * ftx margin api * appveyor fixes * more appveyor issues + test addition * more appveyor issues + test addition * remove unnecessary * testing * testing, fixing okex api, error fix * git merge fix * go sum * glorious changes and error fix * rm vb * more glorious changes and go mod tidy * fixed now * okex testing upgrade * old config migration and batch fetching fix * added test * glorious requested changes WIP * tested and fixed * go fmted * go fmt and test fix * additional funcs and tests for fundingRates * OKEX tested and fixed * appveyor fixes * ineff assign * 1 glorious change * error fix * typo * shazbert changes * glorious code changes and path fixing huobi WIP * adding assetType to accountinfo functions * fixing panic * panic fix and updating account info wrappers WIP * updateaccountinfo updated * testing WIP binance USDT n Coin Margined and Kraken Futures * auth functions tested and fixed * added test * config reverted * shazbert and glorious changes * shazbert and glorious changes * latest changes and portfolio update * go fmt change: * remove commented codes * improved error checking * index out of range fix * rm ln * critical nit * glorious latest changes * appveyor changes * shazbert change * easier readability * latest glorious changes * shadow dec * assetstore updated * last change * another last change * merge changes * go mod tidy * thrasher requested changes wip * improving struct layouts * appveyor go fmt * remove unnecessary code * shazbert changes * small change * oopsie * tidy * configtest reverted * error fix * oopsie * for what * test patch fix * insecurities * fixing tests * fix config
This commit is contained in:
576
exchanges/kraken/futures_types.go
Normal file
576
exchanges/kraken/futures_types.go
Normal file
@@ -0,0 +1,576 @@
|
||||
package kraken
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
)
|
||||
|
||||
var (
|
||||
validOrderTypes = map[order.Type]string{
|
||||
order.ImmediateOrCancel: "ioc",
|
||||
order.Limit: "lmt",
|
||||
order.Stop: "stp",
|
||||
order.PostOnly: "post",
|
||||
order.TakeProfit: "take_profit",
|
||||
}
|
||||
|
||||
validSide = []string{"buy", "sell"}
|
||||
|
||||
validTriggerSignal = []string{"mark", "index", "last"}
|
||||
|
||||
validReduceOnly = []string{"true", "false"}
|
||||
|
||||
validBatchOrderType = []string{
|
||||
"edit", "cancel", "send",
|
||||
}
|
||||
)
|
||||
|
||||
// WSFuturesTickerData stores ws ticker data for futures websocket
|
||||
type WSFuturesTickerData struct {
|
||||
Time int64 `json:"time"`
|
||||
Feed string `json:"feed"`
|
||||
ProductID string `json:"product_id"`
|
||||
Bid float64 `json:"bid"`
|
||||
Ask float64 `json:"ask"`
|
||||
BidSize float64 `json:"bid_size"`
|
||||
AskSize float64 `json:"ask_size"`
|
||||
Volume float64 `json:"volume"`
|
||||
DTM float64 `json:"dtm"`
|
||||
Leverage string `json:"leverage"`
|
||||
Index float64 `json:"index"`
|
||||
Premium float64 `json:"premium"`
|
||||
Last float64 `json:"last"`
|
||||
Change float64 `json:"change"`
|
||||
Suspended bool `json:"suspended"`
|
||||
Tag string `json:"tag"`
|
||||
Pair string `json:"pair"`
|
||||
OpenInterest float64 `json:"openinterest"`
|
||||
MarkPrice float64 `json:"markPrice"`
|
||||
MaturityTime int64 `json:"maturityTime"`
|
||||
FundingRate float64 `json:"funding_rate"`
|
||||
FundingRatePrediction float64 `json:"funding_rate_prediction"`
|
||||
RelativeFundingRate float64 `json:"relative_funding_rate"`
|
||||
RelativeFundingRatePrediction float64 `json:"relative_funding_rate_prediction"`
|
||||
NextFundingRateTime int64 `json:"next_funding_rate_time"`
|
||||
}
|
||||
|
||||
// WsFuturesTradeData stores public trade data for futures websocket
|
||||
type WsFuturesTradeData struct {
|
||||
Feed string `json:"feed"`
|
||||
ProductID string `json:"product_id"`
|
||||
Trades []struct {
|
||||
Feed string `json:"feed"`
|
||||
ProductID string `json:"product_id"`
|
||||
Side string `json:"side"`
|
||||
ProductType string `json:"type"`
|
||||
Seq int64 `json:"seq"`
|
||||
Time int64 `json:"time"`
|
||||
Quantity float64 `json:"qty"`
|
||||
Price float64 `json:"price"`
|
||||
} `json:"trades"`
|
||||
}
|
||||
|
||||
// WsFuturesTickerLite stores ticker lite data for futures websocket
|
||||
type WsFuturesTickerLite struct {
|
||||
Feed string `json:"feed"`
|
||||
ProductID string `json:"product_id"`
|
||||
Bid float64 `json:"bid"`
|
||||
Ask float64 `json:"ask"`
|
||||
Change float64 `json:"change"`
|
||||
Premium float64 `json:"premium"`
|
||||
Volume float64 `json:"volume"`
|
||||
Tag string `json:"tag"`
|
||||
Pair string `json:"pair"`
|
||||
DTM float64 `json:"dtm"`
|
||||
}
|
||||
|
||||
// WsFuturesOB stores orderbook data for futures websocket
|
||||
type WsFuturesOB struct {
|
||||
Feed string `json:"feed"`
|
||||
ProductID string `json:"product_id"`
|
||||
Seq int64 `json:"seq"`
|
||||
Bids []wsOBItem `json:"bids"`
|
||||
Asks []wsOBItem `json:"asks"`
|
||||
}
|
||||
|
||||
type wsOBItem struct {
|
||||
Price float64 `json:"price"`
|
||||
Quantity float64 `json:"qty"`
|
||||
}
|
||||
|
||||
// WsVerboseOpenOrders stores verbose open orders data for futures websocket
|
||||
type WsVerboseOpenOrders struct {
|
||||
Feed string `json:"feed"`
|
||||
Account string `json:"account"`
|
||||
Orders []struct {
|
||||
Instrument string `json:"instrument"`
|
||||
Time int64 `json:"time"`
|
||||
LastUpdateTime int64 `json:"last_update_time"`
|
||||
Qty float64 `json:"qty"`
|
||||
Filled float64 `json:"filled"`
|
||||
LimitPrice float64 `json:"limit_price"`
|
||||
StopPrice float64 `json:"stop_price"`
|
||||
OrderType string `json:"type"`
|
||||
OrderID string `json:"order_id"`
|
||||
Direction int64 `json:"direction"`
|
||||
ReduceOnly bool `json:"reduce_only"`
|
||||
} `json:"orders"`
|
||||
}
|
||||
|
||||
// WsOpenPositions stores open positions data for futures websocket
|
||||
type WsOpenPositions struct {
|
||||
Feed string `json:"feed"`
|
||||
Account string `json:"account"`
|
||||
Positions []struct {
|
||||
Instrument string `json:"instrument"`
|
||||
Balance float64 `json:"balance"`
|
||||
EntryPrice float64 `json:"entry_price"`
|
||||
MarkPrice float64 `json:"mark_price"`
|
||||
IndexPrice float64 `json:"index_price"`
|
||||
ProfitAndLoss float64 `json:"pnl"`
|
||||
} `json:"positions"`
|
||||
}
|
||||
|
||||
// WsFuturesAccountLog stores account log data for futures websocket
|
||||
type WsFuturesAccountLog struct {
|
||||
Feed string `json:"feed"`
|
||||
Logs []struct {
|
||||
ID int64 `json:"id"`
|
||||
Date string `json:"date"`
|
||||
Asset string `json:"asset"`
|
||||
Info string `json:"info"`
|
||||
BookingUID string `json:"booking_uid"`
|
||||
MarginAccount string `json:"margin_account"`
|
||||
OldBalance float64 `json:"old_balance"`
|
||||
NewBalance float64 `json:"new_balance"`
|
||||
OldAverageEntry float64 `json:"old_average_entry"`
|
||||
NewAverageEntry float64 `json:"new_average_entry"`
|
||||
TradePrice float64 `json:"trade_price"`
|
||||
MarkPrice float64 `json:"mark_price"`
|
||||
RealizedPNL float64 `json:"realized_pnl"`
|
||||
Fee float64 `json:"fee"`
|
||||
Execution string `json:"execution"`
|
||||
Collateral string `json:"collateral"`
|
||||
FundingRate float64 `json:"funding_rate"`
|
||||
RealizedFunding float64 `json:"realized_funding"`
|
||||
} `json:"logs"`
|
||||
}
|
||||
|
||||
// WsFuturesFillsData stores fills data for futures websocket
|
||||
type WsFuturesFillsData struct {
|
||||
Feed string `json:"feed"`
|
||||
Account string `json:"account"`
|
||||
Fills []struct {
|
||||
Instrument string `json:"instrument"`
|
||||
Time int64 `json:"time"`
|
||||
Price float64 `json:"price"`
|
||||
Seq int64 `json:"seq"`
|
||||
Buy bool `json:"buy"`
|
||||
Quantity float64 `json:"qty"`
|
||||
OrderID string `json:"order_id"`
|
||||
ClientOrderID string `json:"cli_order_id"`
|
||||
FillID string `json:"fill_id"`
|
||||
FillType string `json:"fill_type"`
|
||||
} `json:"fills"`
|
||||
}
|
||||
|
||||
// WsFuturesOpenOrders stores open orders data for futures websocket
|
||||
type WsFuturesOpenOrders struct {
|
||||
Feed string `json:"feed"`
|
||||
Account string `json:"account"`
|
||||
Orders []struct {
|
||||
Instrument string `json:"instrument"`
|
||||
Time int64 `json:"time"`
|
||||
LastUpdateTime int64 `json:"last_update_time"`
|
||||
Qty float64 `json:"qty"`
|
||||
Filled float64 `json:"filled"`
|
||||
LimitPrice float64 `json:"limit_price"`
|
||||
StopPrice float64 `json:"stop_price"`
|
||||
OrderType string `json:"order_type"`
|
||||
OrderID string `json:"order_id"`
|
||||
Direction string `json:"direction"`
|
||||
ReduceOnly bool `json:"reduce_only"`
|
||||
} `json:"orders"`
|
||||
}
|
||||
|
||||
// WsAccountBalancesAndMargin stores account balances and margin data for futures websocket
|
||||
type WsAccountBalancesAndMargin struct {
|
||||
Seq int64 `json:"seq"`
|
||||
Feed string `json:"feed"`
|
||||
Account string `json:"account"`
|
||||
MarginAccounts []struct {
|
||||
Name string `json:"name"`
|
||||
PortfolioValue float64 `json:"pv"`
|
||||
Balance float64 `json:"balance"`
|
||||
Funding float64 `json:"funding"`
|
||||
MaintenanceMargin float64 `json:"mm"`
|
||||
ProfitAndLoss float64 `json:"pnl"`
|
||||
InitialMargin float64 `json:"im"`
|
||||
AM float64 `json:"am"`
|
||||
} `json:"margin_accounts"`
|
||||
}
|
||||
|
||||
// WsFuturesNotifications stores notifications data for futures websocket
|
||||
type WsFuturesNotifications struct {
|
||||
Feed string `json:"feed"`
|
||||
Notifications []struct {
|
||||
ID int64 `json:"id"`
|
||||
NotificationType string `json:"notificationType"`
|
||||
Priority string `json:"priority"`
|
||||
Note string `json:"note"`
|
||||
EffectiveTime int64 `json:"effective_time"`
|
||||
}
|
||||
}
|
||||
|
||||
type assetTranslatorStore struct {
|
||||
l sync.RWMutex
|
||||
Assets map[string]string
|
||||
}
|
||||
|
||||
// FuturesOrderbookData stores orderbook data for futures
|
||||
type FuturesOrderbookData struct {
|
||||
ServerTime string `json:"serverTime"`
|
||||
Orderbook struct {
|
||||
Bids [][2]float64 `json:"bids"`
|
||||
Asks [][2]float64 `json:"asks"`
|
||||
} `json:"orderBook"`
|
||||
}
|
||||
|
||||
// TimeResponse type
|
||||
type TimeResponse struct {
|
||||
Unixtime int64 `json:"unixtime"`
|
||||
Rfc1123 string `json:"rfc1123"`
|
||||
}
|
||||
|
||||
// FuturesInstrumentData stores info for futures market
|
||||
type FuturesInstrumentData struct {
|
||||
Instruments []struct {
|
||||
Symbol string `json:"symbol"`
|
||||
FutureType string `json:"type"`
|
||||
Underlying string `json:"underlying"`
|
||||
LastTradingTime string `json:"lastTradingTime"`
|
||||
TickSize float64 `json:"tickSize"`
|
||||
ContractSize float64 `json:"contractSize"`
|
||||
Tradable bool `json:"tradeable"`
|
||||
MarginLevels []struct {
|
||||
Contracts float64 `json:"contracts"`
|
||||
InitialMargin float64 `json:"initialMargin"`
|
||||
MaintenanceMargin float64 `json:"maintenanceMargin"`
|
||||
} `json:"marginLevels"`
|
||||
} `json:"instruments"`
|
||||
}
|
||||
|
||||
// FuturesTradeHistoryData stores trade history data for futures
|
||||
type FuturesTradeHistoryData struct {
|
||||
History []struct {
|
||||
Time string `json:"time"`
|
||||
TradeID int64 `json:"trade_id"`
|
||||
Price float64 `json:"price"`
|
||||
Size float64 `json:"size"`
|
||||
Side string `json:"side"`
|
||||
TradeType string `json:"type"`
|
||||
} `json:"history"`
|
||||
}
|
||||
|
||||
// FuturesTickerData stores info for futures ticker
|
||||
type FuturesTickerData struct {
|
||||
Tickers []struct {
|
||||
Tag string `json:"tag"`
|
||||
Pair string `json:"pair"`
|
||||
Symbol string `json:"symbol"`
|
||||
MarkPrice float64 `json:"markPrice"`
|
||||
Bid float64 `json:"bid"`
|
||||
BidSize float64 `json:"bidSize"`
|
||||
Ask float64 `json:"ask"`
|
||||
AskSize float64 `json:"askSize"`
|
||||
Vol24h float64 `json:"vol24h"`
|
||||
OpenInterest float64 `json:"openInterest"`
|
||||
Open24H float64 `json:"open24h"`
|
||||
Last float64 `json:"last"`
|
||||
LastTime string `json:"lastTime"`
|
||||
LastSize float64 `json:"lastSize"`
|
||||
Suspended bool `json:"suspended"`
|
||||
FundingRate float64 `json:"fundingRate"`
|
||||
FundingRatePrediction float64 `json:"fundingRatePrediction"`
|
||||
} `json:"tickers"`
|
||||
ServerTime string `json:"serverTime"`
|
||||
}
|
||||
|
||||
// FuturesEditedOrderData stores an edited order's data
|
||||
type FuturesEditedOrderData struct {
|
||||
ServerTime string `json:"serverTime"`
|
||||
EditStatus struct {
|
||||
Status string `json:"status"`
|
||||
OrderID string `json:"orderId"`
|
||||
ReceivedTime string `json:"receivedTime"`
|
||||
OrderEvents []struct {
|
||||
Old FuturesOrderData `json:"old"`
|
||||
New FuturesOrderData `json:"new"`
|
||||
} `json:"orderEvents"`
|
||||
ReduceQuantity string `json:"reduceQuantity"`
|
||||
DataType string `json:"type"`
|
||||
} `json:"editStatus"`
|
||||
}
|
||||
|
||||
// FuturesSendOrderData stores send order data
|
||||
type FuturesSendOrderData struct {
|
||||
SendStatus struct {
|
||||
OrderID string `json:"orderId"`
|
||||
Status string `json:"status"`
|
||||
ReceivedTime string `json:"receivedTime"`
|
||||
OrderEvents []struct {
|
||||
UID string `json:"uid"`
|
||||
Order FuturesOrderData `json:"order"`
|
||||
Reason string `json:"reason"`
|
||||
DataType string `json:"type"`
|
||||
} `json:"orderEvents"`
|
||||
} `json:"sendStatus"`
|
||||
ServerTime string `json:"serverTime"`
|
||||
}
|
||||
|
||||
// FuturesOrderData stores order data
|
||||
type FuturesOrderData struct {
|
||||
OrderID string `json:"orderId"`
|
||||
ClientOrderID string `json:"cliOrderId"`
|
||||
OrderType string `json:"type"`
|
||||
Symbol string `json:"symbol"`
|
||||
Side string `json:"side"`
|
||||
Quantity float64 `json:"quantity"`
|
||||
Filled float64 `json:"filled"`
|
||||
LimitPrice float64 `json:"limitPrice"`
|
||||
ReduceOnly bool `json:"reduceOnly"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
LastUpdateTimestamp string `json:"lastUpdateTimestamp"`
|
||||
}
|
||||
|
||||
// FuturesCancelOrderData stores cancel order data for futures
|
||||
type FuturesCancelOrderData struct {
|
||||
CancelStatus struct {
|
||||
Status string `json:"status"`
|
||||
OrderID string `json:"order_id"`
|
||||
ReceivedTime string `json:"receivedTime"`
|
||||
OrderEvents []struct {
|
||||
UID string `json:"uid"`
|
||||
Order FuturesOrderData `json:"order"`
|
||||
DataType string `json:"type"`
|
||||
} `json:"orderEvents"`
|
||||
} `json:"cancelStatus"`
|
||||
ServerTime string `json:"serverTime"`
|
||||
}
|
||||
|
||||
// FuturesFillsData stores fills data
|
||||
type FuturesFillsData struct {
|
||||
Fills []struct {
|
||||
FillID string `json:"fill_id"`
|
||||
Symbol string `json:"symbol"`
|
||||
Side string `json:"buy"`
|
||||
OrderID string `json:"order_id"`
|
||||
Size float64 `json:"size"`
|
||||
Price float64 `json:"price"`
|
||||
FillTime string `json:"fillTime"`
|
||||
FillType string `json:"fillType"`
|
||||
} `json:"fills"`
|
||||
ServerTime string `json:"serverTime"`
|
||||
}
|
||||
|
||||
// FuturesTransferData stores transfer data
|
||||
type FuturesTransferData struct {
|
||||
Result string `json:"result"`
|
||||
ServerTime string `json:"serverTime"`
|
||||
}
|
||||
|
||||
// FuturesOpenPositions stores open positions data for futures
|
||||
type FuturesOpenPositions struct {
|
||||
OpenPositions []struct {
|
||||
Side string `json:"side"`
|
||||
Symbol string `json:"symbol"`
|
||||
Price float64 `json:"price"`
|
||||
FillTime string `json:"fillTime"`
|
||||
Size float64 `json:"size"`
|
||||
UnrealizedFunding float64 `json:"unrealizedFunding"`
|
||||
} `json:"openPositions"`
|
||||
ServerTime string `json:"serverTime"`
|
||||
}
|
||||
|
||||
// FuturesNotificationData stores notification data
|
||||
type FuturesNotificationData struct {
|
||||
Notifications []struct {
|
||||
NotificationType string `json:"type"`
|
||||
Priority string `json:"priority"`
|
||||
Note string `json:"note"`
|
||||
EffectiveTime string `json:"effectiveTime"`
|
||||
} `json:"notifcations"`
|
||||
ServerTime string `json:"serverTime"`
|
||||
}
|
||||
|
||||
// FuturesAccountsData stores account data
|
||||
type FuturesAccountsData struct {
|
||||
ServerTime string `json:"serverTime"`
|
||||
Accounts map[string]AccountsData `json:"accounts"`
|
||||
}
|
||||
|
||||
// AccountsData stores data of an account
|
||||
type AccountsData struct {
|
||||
AccType string `json:"type"`
|
||||
Currency string `json:"currency"`
|
||||
Balances map[string]float64 `json:"balances"`
|
||||
Auxiliary struct {
|
||||
AvailableFunds float64 `json:"af"`
|
||||
ProfitAndLoss float64 `json:"pnl"`
|
||||
PortfolioValue float64 `json:"pv"`
|
||||
} `json:"auxiliary"`
|
||||
MarginRequirements struct {
|
||||
InitialMargin float64 `json:"im"`
|
||||
MaintenanceMargin float64 `json:"mm"`
|
||||
LiquidationThreshold float64 `json:"lt"`
|
||||
TerminationThreshold float64 `json:"tt"`
|
||||
} `json:"marginRequirements"`
|
||||
TriggerEstimates struct {
|
||||
InitialMargin float64 `json:"im"`
|
||||
MaintenanceMargin float64 `json:"mm"`
|
||||
LiquidationThreshold float64 `json:"lt"`
|
||||
TerminationThreshold float64 `json:"tt"`
|
||||
} `json:"triggerEstimates"`
|
||||
}
|
||||
|
||||
// CancelAllOrdersData stores order data for all cancelled orders
|
||||
type CancelAllOrdersData struct {
|
||||
CancelStatus struct {
|
||||
ReceivedTime string `json:"receivedTime"`
|
||||
CancelOnly string `json:"cancelOnly"`
|
||||
Status string `json:"status"`
|
||||
CancelledOrders []struct {
|
||||
OrderID string `json:"order_id"`
|
||||
} `json:"cancelledOrders"`
|
||||
OrderEvents []struct {
|
||||
UID string `json:"uid"`
|
||||
} `json:"uid"`
|
||||
Order FuturesOrderData `json:"order"`
|
||||
DataType string `json:"type"`
|
||||
} `json:"cancelStatus"`
|
||||
ServerTime string `json:"serverTime"`
|
||||
}
|
||||
|
||||
// CancelOrdersAfterData stores data of all orders after a certain time that are cancelled
|
||||
type CancelOrdersAfterData struct {
|
||||
Result string `json:"result"`
|
||||
Status struct {
|
||||
CurrentTime string `json:"currentTime"`
|
||||
TriggerTime string `json:"triggerTime"`
|
||||
} `json:"status"`
|
||||
ServerTime string `json:"serverTime"`
|
||||
}
|
||||
|
||||
// RecentOrderData stores order data of a recent order
|
||||
type RecentOrderData struct {
|
||||
UID string `json:"uid"`
|
||||
AccountID string `json:"accountId"`
|
||||
Tradeable string `json:"tradeable"`
|
||||
Direction string `json:"direction"`
|
||||
Quantity float64 `json:"quantity,string"`
|
||||
Filled float64 `json:"filled,string"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
LimitPrice float64 `json:"limitPrice,string"`
|
||||
OrderType string `json:"orderType"`
|
||||
ClientID string `json:"clientId"`
|
||||
StopPrice float64 `json:"stopPrice,string"`
|
||||
}
|
||||
|
||||
// FOpenOrdersData stores open orders data for futures
|
||||
type FOpenOrdersData struct {
|
||||
OrderID string `json:"order_id"`
|
||||
ClientOrderID string `json:"cliOrdId"`
|
||||
Symbol string `json:"symbol"`
|
||||
Side string `json:"side"`
|
||||
OrderType string `json:"orderType"`
|
||||
LimitPrice float64 `json:"limitPrice"`
|
||||
StopPrice float64 `json:"stopPrice"`
|
||||
UnfilledSize float64 `json:"unfilledSize"`
|
||||
ReceivedTime string `json:"receivedTime"`
|
||||
Status string `json:"status"`
|
||||
FilledSize float64 `json:"filledSize"`
|
||||
ReduceOnly bool `json:"reduceOnly"`
|
||||
TriggerSignal string `json:"triggerSignal"`
|
||||
LastUpdateTime string `json:"lastUpdateTime"`
|
||||
}
|
||||
|
||||
// FuturesRecentOrdersData stores recent orders data
|
||||
type FuturesRecentOrdersData struct {
|
||||
OrderEvents []struct {
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Event struct {
|
||||
Timestamp string `json:"timestamp"`
|
||||
UID string `json:"uid"`
|
||||
OrderPlaced struct {
|
||||
RecentOrder RecentOrderData `json:"order"`
|
||||
Reason string `json:"reason"`
|
||||
} `json:"orderPlaced"`
|
||||
OrderCancelled struct {
|
||||
RecentOrder RecentOrderData `json:"order"`
|
||||
Reason string `json:"reason"`
|
||||
} `json:"orderCancelled"`
|
||||
OrderRejected struct {
|
||||
RecentOrder RecentOrderData `json:"order"`
|
||||
Reason string `json:"reason"`
|
||||
} `json:"orderRejected"`
|
||||
ExecutionEvent struct {
|
||||
Execution ExecutionData `json:"execution"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
Quantity float64 `json:"quantity"`
|
||||
Price float64 `json:"price"`
|
||||
MarkPrice float64 `json:"markPrice"`
|
||||
LimitFilled bool `json:"limitFilled"`
|
||||
} `json:"executionEvent"`
|
||||
} `json:"event"`
|
||||
} `json:"orderEvents"`
|
||||
}
|
||||
|
||||
// BatchOrderData stores batch order data
|
||||
type BatchOrderData struct {
|
||||
Result bool `json:"result"`
|
||||
ServerTime string `json:"serverTime"`
|
||||
BatchStatus []struct {
|
||||
Status string `json:"status"`
|
||||
OrderTag string `json:"order_tag"`
|
||||
OrderID string `json:"order_id"`
|
||||
DateTimeReceived string `json:"dateTimeReceieved"`
|
||||
OrderEvents []struct {
|
||||
OrderPlaced FuturesOrderData `json:"orderPlaced"`
|
||||
ReduceOnly bool `json:"reduceOnly"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
OldEditedOrder FuturesOrderData `json:"old"`
|
||||
NewEditedOrder FuturesOrderData `json:"new"`
|
||||
UID string `json:"uid"`
|
||||
RequestType string `json:"requestType"`
|
||||
} `json:"orderEvents"`
|
||||
} `json:"batchStatus"`
|
||||
}
|
||||
|
||||
// PlaceBatchOrderData stores data required to place a batch order
|
||||
type PlaceBatchOrderData struct {
|
||||
PlaceOrderType string `json:"order,omitempty"`
|
||||
OrderType string `json:"orderType,omitempty"`
|
||||
OrderTag string `json:"order_tag,omitempty"`
|
||||
Symbol string `json:"symbol,omitempty"`
|
||||
Side string `json:"side,omitempty"`
|
||||
Size float64 `json:"size,omitempty"`
|
||||
LimitPrice float64 `json:"limitPrice,omitempty"`
|
||||
StopPrice float64 `json:"stopPrice,omitempty"`
|
||||
ClientOrderID int64 `json:"cliOrdId,omitempty"`
|
||||
ReduceOnly string `json:"reduceOnly,omitempty"`
|
||||
OrderID string `json:"order_id,omitempty"`
|
||||
}
|
||||
|
||||
// ExecutionData stores execution data
|
||||
type ExecutionData struct {
|
||||
UID string `json:"uid"`
|
||||
TakerOrder RecentOrderData `json:"takerOrder"`
|
||||
}
|
||||
|
||||
// FuturesOpenOrdersData stores open orders data for futures
|
||||
type FuturesOpenOrdersData struct {
|
||||
Result string `json:"result"`
|
||||
OpenOrders []FOpenOrdersData `json:"openOrders"`
|
||||
ServerTime string `json:"serverTime"`
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package kraken
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@@ -15,53 +16,18 @@ import (
|
||||
"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/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
|
||||
"github.com/thrasher-corp/gocryptotrader/log"
|
||||
)
|
||||
|
||||
const (
|
||||
krakenAPIURL = "https://api.kraken.com"
|
||||
krakenAPIVersion = "0"
|
||||
krakenServerTime = "Time"
|
||||
krakenAssets = "Assets"
|
||||
krakenAssetPairs = "AssetPairs"
|
||||
krakenTicker = "Ticker"
|
||||
krakenOHLC = "OHLC"
|
||||
krakenDepth = "Depth"
|
||||
krakenTrades = "Trades"
|
||||
krakenSpread = "Spread"
|
||||
krakenBalance = "Balance"
|
||||
krakenTradeBalance = "TradeBalance"
|
||||
krakenOpenOrders = "OpenOrders"
|
||||
krakenClosedOrders = "ClosedOrders"
|
||||
krakenQueryOrders = "QueryOrders"
|
||||
krakenTradeHistory = "TradesHistory"
|
||||
krakenQueryTrades = "QueryTrades"
|
||||
krakenOpenPositions = "OpenPositions"
|
||||
krakenLedgers = "Ledgers"
|
||||
krakenQueryLedgers = "QueryLedgers"
|
||||
krakenTradeVolume = "TradeVolume"
|
||||
krakenOrderCancel = "CancelOrder"
|
||||
krakenOrderPlace = "AddOrder"
|
||||
krakenWithdrawInfo = "WithdrawInfo"
|
||||
krakenWithdraw = "Withdraw"
|
||||
krakenDepositMethods = "DepositMethods"
|
||||
krakenDepositAddresses = "DepositAddresses"
|
||||
krakenWithdrawStatus = "WithdrawStatus"
|
||||
krakenWithdrawCancel = "WithdrawCancel"
|
||||
krakenWebsocketToken = "GetWebSocketsToken"
|
||||
|
||||
// Rate limit consts
|
||||
krakenRateInterval = time.Second
|
||||
krakenRequestRate = 1
|
||||
|
||||
// Status consts
|
||||
statusOpen = "open"
|
||||
)
|
||||
|
||||
var (
|
||||
assetTranslator assetTranslatorStore
|
||||
krakenAPIURL = "https://api.kraken.com"
|
||||
krakenFuturesURL = "https://futures.kraken.com"
|
||||
futuresURL = "https://futures.kraken.com/derivatives"
|
||||
krakenSpotVersion = "0"
|
||||
krakenFuturesVersion = "3"
|
||||
)
|
||||
|
||||
// Kraken is the overarching type across the alphapoint package
|
||||
@@ -72,14 +38,14 @@ type Kraken struct {
|
||||
|
||||
// GetServerTime returns current server time
|
||||
func (k *Kraken) GetServerTime() (TimeResponse, error) {
|
||||
path := fmt.Sprintf("%s/%s/public/%s", k.API.Endpoints.URL, krakenAPIVersion, krakenServerTime)
|
||||
path := fmt.Sprintf("/%s/public/%s", krakenAPIVersion, krakenServerTime)
|
||||
|
||||
var response struct {
|
||||
Error []string `json:"error"`
|
||||
Result TimeResponse `json:"result"`
|
||||
}
|
||||
|
||||
if err := k.SendHTTPRequest(path, &response); err != nil {
|
||||
if err := k.SendHTTPRequest(exchange.RestSpot, path, &response); err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
|
||||
@@ -93,55 +59,70 @@ func (k *Kraken) SeedAssets() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range assets {
|
||||
assetTranslator.Seed(k, v.Altname)
|
||||
for orig, val := range assets {
|
||||
assetTranslator.Seed(orig, val.Altname)
|
||||
}
|
||||
|
||||
assetPairs, err := k.GetAssetPairs()
|
||||
assetPairs, err := k.GetAssetPairs([]string{}, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range assetPairs {
|
||||
assetTranslator.Seed(k, v.Altname)
|
||||
for k := range assetPairs {
|
||||
assetTranslator.Seed(k, assetPairs[k].Altname)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAssets returns a full asset list
|
||||
func (k *Kraken) GetAssets() (map[string]*Asset, error) {
|
||||
path := fmt.Sprintf("%s/%s/public/%s", k.API.Endpoints.URL, krakenAPIVersion, krakenAssets)
|
||||
path := fmt.Sprintf("/%s/public/%s", krakenAPIVersion, krakenAssets)
|
||||
|
||||
var response struct {
|
||||
Error []string `json:"error"`
|
||||
Result map[string]*Asset `json:"result"`
|
||||
}
|
||||
|
||||
if err := k.SendHTTPRequest(path, &response); err != nil {
|
||||
if err := k.SendHTTPRequest(exchange.RestSpot, path, &response); err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
return response.Result, GetError(response.Error)
|
||||
}
|
||||
|
||||
// GetAssetPairs returns a full asset pair list
|
||||
func (k *Kraken) GetAssetPairs() (map[string]*AssetPairs, error) {
|
||||
path := fmt.Sprintf("%s/%s/public/%s", k.API.Endpoints.URL, krakenAPIVersion, krakenAssetPairs)
|
||||
|
||||
var response struct {
|
||||
Error []string `json:"error"`
|
||||
Result map[string]*AssetPairs `json:"result"`
|
||||
// Parameter 'info' only supports 4 strings: "fees", "leverage", "margin", "info" <- (default)
|
||||
func (k *Kraken) GetAssetPairs(assetPairs []string, info string) (map[string]AssetPairs, error) {
|
||||
path := fmt.Sprintf("/%s/public/%s", krakenAPIVersion, krakenAssetPairs)
|
||||
params := url.Values{}
|
||||
var assets string
|
||||
if len(assetPairs) != 0 {
|
||||
assets = strings.Join(assetPairs, ",")
|
||||
params.Set("pair", assets)
|
||||
}
|
||||
|
||||
if err := k.SendHTTPRequest(path, &response); err != nil {
|
||||
var response struct {
|
||||
Error []string `json:"error"`
|
||||
Result map[string]AssetPairs `json:"result"`
|
||||
}
|
||||
if info != "" {
|
||||
if info != "margin" && info != "leverage" && info != "fees" && info != "info" {
|
||||
return response.Result, errors.New("parameter info can only be 'asset', 'margin', 'fees' or 'leverage'")
|
||||
}
|
||||
params.Set("info", info)
|
||||
}
|
||||
if err := k.SendHTTPRequest(exchange.RestSpot, path+params.Encode(), &response); err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
return response.Result, GetError(response.Error)
|
||||
}
|
||||
|
||||
// GetTicker returns ticker information from kraken
|
||||
func (k *Kraken) GetTicker(symbol string) (Ticker, error) {
|
||||
func (k *Kraken) GetTicker(symbol currency.Pair) (Ticker, error) {
|
||||
tick := Ticker{}
|
||||
values := url.Values{}
|
||||
values.Set("pair", symbol)
|
||||
symbolValue, err := k.FormatSymbol(symbol, asset.Spot)
|
||||
if err != nil {
|
||||
return tick, err
|
||||
}
|
||||
values.Set("pair", symbolValue)
|
||||
|
||||
type Response struct {
|
||||
Error []interface{} `json:"error"`
|
||||
@@ -149,9 +130,9 @@ func (k *Kraken) GetTicker(symbol string) (Ticker, error) {
|
||||
}
|
||||
|
||||
resp := Response{}
|
||||
path := fmt.Sprintf("%s/%s/public/%s?%s", k.API.Endpoints.URL, krakenAPIVersion, krakenTicker, values.Encode())
|
||||
path := fmt.Sprintf("/%s/public/%s?%s", krakenAPIVersion, krakenTicker, values.Encode())
|
||||
|
||||
err := k.SendHTTPRequest(path, &resp)
|
||||
err = k.SendHTTPRequest(exchange.RestSpot, path, &resp)
|
||||
if err != nil {
|
||||
return tick, err
|
||||
}
|
||||
@@ -187,9 +168,9 @@ func (k *Kraken) GetTickers(pairList string) (map[string]Ticker, error) {
|
||||
}
|
||||
|
||||
resp := Response{}
|
||||
path := fmt.Sprintf("%s/%s/public/%s?%s", k.API.Endpoints.URL, krakenAPIVersion, krakenTicker, values.Encode())
|
||||
path := fmt.Sprintf("/%s/public/%s?%s", krakenAPIVersion, krakenTicker, values.Encode())
|
||||
|
||||
err := k.SendHTTPRequest(path, &resp)
|
||||
err := k.SendHTTPRequest(exchange.RestSpot, path, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -217,9 +198,17 @@ func (k *Kraken) GetTickers(pairList string) (map[string]Ticker, error) {
|
||||
}
|
||||
|
||||
// GetOHLC returns an array of open high low close values of a currency pair
|
||||
func (k *Kraken) GetOHLC(symbol, interval string) ([]OpenHighLowClose, error) {
|
||||
func (k *Kraken) GetOHLC(symbol currency.Pair, interval string) ([]OpenHighLowClose, error) {
|
||||
values := url.Values{}
|
||||
values.Set("pair", symbol)
|
||||
symbolValue, err := k.FormatSymbol(symbol, asset.Spot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
translatedAsset := assetTranslator.LookupCurrency(symbolValue)
|
||||
if translatedAsset == "" {
|
||||
translatedAsset = symbolValue
|
||||
}
|
||||
values.Set("pair", translatedAsset)
|
||||
values.Set("interval", interval)
|
||||
type Response struct {
|
||||
Error []interface{} `json:"error"`
|
||||
@@ -229,9 +218,9 @@ func (k *Kraken) GetOHLC(symbol, interval string) ([]OpenHighLowClose, error) {
|
||||
var OHLC []OpenHighLowClose
|
||||
var result Response
|
||||
|
||||
path := fmt.Sprintf("%s/%s/public/%s?%s", k.API.Endpoints.URL, krakenAPIVersion, krakenOHLC, values.Encode())
|
||||
path := fmt.Sprintf("/%s/public/%s?%s", krakenAPIVersion, krakenOHLC, values.Encode())
|
||||
|
||||
err := k.SendHTTPRequest(path, &result)
|
||||
err = k.SendHTTPRequest(exchange.RestSpot, path, &result)
|
||||
if err != nil {
|
||||
return OHLC, err
|
||||
}
|
||||
@@ -240,12 +229,12 @@ func (k *Kraken) GetOHLC(symbol, interval string) ([]OpenHighLowClose, error) {
|
||||
return OHLC, fmt.Errorf("getOHLC error: %s", result.Error)
|
||||
}
|
||||
|
||||
_, ok := result.Data[symbol].([]interface{})
|
||||
_, ok := result.Data[translatedAsset].([]interface{})
|
||||
if !ok {
|
||||
return nil, errors.New("invalid data returned")
|
||||
}
|
||||
|
||||
for _, y := range result.Data[symbol].([]interface{}) {
|
||||
for _, y := range result.Data[translatedAsset].([]interface{}) {
|
||||
o := OpenHighLowClose{}
|
||||
for i, x := range y.([]interface{}) {
|
||||
switch i {
|
||||
@@ -273,15 +262,17 @@ func (k *Kraken) GetOHLC(symbol, interval string) ([]OpenHighLowClose, error) {
|
||||
}
|
||||
|
||||
// GetDepth returns the orderbook for a particular currency
|
||||
func (k *Kraken) GetDepth(symbol string) (Orderbook, error) {
|
||||
values := url.Values{}
|
||||
values.Set("pair", symbol)
|
||||
|
||||
func (k *Kraken) GetDepth(symbol currency.Pair) (Orderbook, error) {
|
||||
var result interface{}
|
||||
var orderBook Orderbook
|
||||
|
||||
path := fmt.Sprintf("%s/%s/public/%s?%s", k.API.Endpoints.URL, krakenAPIVersion, krakenDepth, values.Encode())
|
||||
err := k.SendHTTPRequest(path, &result)
|
||||
values := url.Values{}
|
||||
symbolValue, err := k.FormatSymbol(symbol, asset.Spot)
|
||||
if err != nil {
|
||||
return orderBook, err
|
||||
}
|
||||
values.Set("pair", symbolValue)
|
||||
path := fmt.Sprintf("/%s/public/%s?%s", krakenAPIVersion, krakenDepth, values.Encode())
|
||||
err = k.SendHTTPRequest(exchange.RestSpot, path, &result)
|
||||
if err != nil {
|
||||
return orderBook, err
|
||||
}
|
||||
@@ -334,16 +325,21 @@ func (k *Kraken) GetDepth(symbol string) (Orderbook, error) {
|
||||
}
|
||||
|
||||
// GetTrades returns current trades on Kraken
|
||||
func (k *Kraken) GetTrades(symbol string) ([]RecentTrades, error) {
|
||||
func (k *Kraken) GetTrades(symbol currency.Pair) ([]RecentTrades, error) {
|
||||
values := url.Values{}
|
||||
values.Set("pair", symbol)
|
||||
symbolValue, err := k.FormatSymbol(symbol, asset.Spot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
translatedAsset := assetTranslator.LookupCurrency(symbolValue)
|
||||
values.Set("pair", translatedAsset)
|
||||
|
||||
var recentTrades []RecentTrades
|
||||
var result interface{}
|
||||
|
||||
path := fmt.Sprintf("%s/%s/public/%s?%s", k.API.Endpoints.URL, krakenAPIVersion, krakenTrades, values.Encode())
|
||||
path := fmt.Sprintf("/%s/public/%s?%s", krakenAPIVersion, krakenTrades, values.Encode())
|
||||
|
||||
err := k.SendHTTPRequest(path, &result)
|
||||
err = k.SendHTTPRequest(exchange.RestSpot, path, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -390,7 +386,7 @@ func (k *Kraken) GetTrades(symbol string) ([]RecentTrades, error) {
|
||||
|
||||
var trades []interface{}
|
||||
var tradesForSymbol interface{}
|
||||
tradesForSymbol, ok = tradeInfo[symbol]
|
||||
tradesForSymbol, ok = tradeInfo[translatedAsset]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no data returned for symbol %v", symbol)
|
||||
}
|
||||
@@ -440,16 +436,20 @@ func (k *Kraken) GetTrades(symbol string) ([]RecentTrades, error) {
|
||||
}
|
||||
|
||||
// GetSpread returns the full spread on Kraken
|
||||
func (k *Kraken) GetSpread(symbol string) ([]Spread, error) {
|
||||
func (k *Kraken) GetSpread(symbol currency.Pair) ([]Spread, error) {
|
||||
values := url.Values{}
|
||||
values.Set("pair", symbol)
|
||||
symbolValue, err := k.FormatSymbol(symbol, asset.Spot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
values.Set("pair", symbolValue)
|
||||
|
||||
var peanutButter []Spread
|
||||
var response interface{}
|
||||
|
||||
path := fmt.Sprintf("%s/%s/public/%s?%s", k.API.Endpoints.URL, krakenAPIVersion, krakenSpread, values.Encode())
|
||||
path := fmt.Sprintf("/%s/public/%s?%s", krakenAPIVersion, krakenSpread, values.Encode())
|
||||
|
||||
err := k.SendHTTPRequest(path, &response)
|
||||
err = k.SendHTTPRequest(exchange.RestSpot, path, &response)
|
||||
if err != nil {
|
||||
return peanutButter, err
|
||||
}
|
||||
@@ -457,7 +457,7 @@ func (k *Kraken) GetSpread(symbol string) ([]Spread, error) {
|
||||
data := response.(map[string]interface{})
|
||||
result := data["result"].(map[string]interface{})
|
||||
|
||||
for _, x := range result[symbol].([]interface{}) {
|
||||
for _, x := range result[symbolValue].([]interface{}) {
|
||||
s := Spread{}
|
||||
for i, y := range x.([]interface{}) {
|
||||
switch i {
|
||||
@@ -481,7 +481,7 @@ func (k *Kraken) GetBalance() (map[string]float64, error) {
|
||||
Result map[string]string `json:"result"`
|
||||
}
|
||||
|
||||
if err := k.SendAuthenticatedHTTPRequest(krakenBalance, url.Values{}, &response); err != nil {
|
||||
if err := k.SendAuthenticatedHTTPRequest(exchange.RestSpot, krakenBalance, url.Values{}, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -507,7 +507,7 @@ func (k *Kraken) GetWithdrawInfo(currency string, amount float64) (WithdrawInfor
|
||||
params.Set("key", "")
|
||||
params.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
|
||||
if err := k.SendAuthenticatedHTTPRequest(krakenWithdrawInfo, params, &response); err != nil {
|
||||
if err := k.SendAuthenticatedHTTPRequest(exchange.RestSpot, krakenWithdrawInfo, params, &response); err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
|
||||
@@ -525,7 +525,7 @@ func (k *Kraken) Withdraw(asset, key string, amount float64) (string, error) {
|
||||
params.Set("key", key)
|
||||
params.Set("amount", fmt.Sprintf("%f", amount))
|
||||
|
||||
if err := k.SendAuthenticatedHTTPRequest(krakenWithdraw, params, &response); err != nil {
|
||||
if err := k.SendAuthenticatedHTTPRequest(exchange.RestSpot, krakenWithdraw, params, &response); err != nil {
|
||||
return response.ReferenceID, err
|
||||
}
|
||||
|
||||
@@ -541,7 +541,7 @@ func (k *Kraken) GetDepositMethods(currency string) ([]DepositMethods, error) {
|
||||
params := url.Values{}
|
||||
params.Set("asset", currency)
|
||||
|
||||
err := k.SendAuthenticatedHTTPRequest(krakenDepositMethods, params, &response)
|
||||
err := k.SendAuthenticatedHTTPRequest(exchange.RestSpot, krakenDepositMethods, params, &response)
|
||||
if err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
@@ -568,7 +568,7 @@ func (k *Kraken) GetTradeBalance(args ...TradeBalanceOptions) (TradeBalanceInfo,
|
||||
Result TradeBalanceInfo `json:"result"`
|
||||
}
|
||||
|
||||
if err := k.SendAuthenticatedHTTPRequest(krakenTradeBalance, params, &response); err != nil {
|
||||
if err := k.SendAuthenticatedHTTPRequest(exchange.RestSpot, krakenTradeBalance, params, &response); err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
|
||||
@@ -592,7 +592,7 @@ func (k *Kraken) GetOpenOrders(args OrderInfoOptions) (OpenOrders, error) {
|
||||
Result OpenOrders `json:"result"`
|
||||
}
|
||||
|
||||
if err := k.SendAuthenticatedHTTPRequest(krakenOpenOrders, params, &response); err != nil {
|
||||
if err := k.SendAuthenticatedHTTPRequest(exchange.RestSpot, krakenOpenOrders, params, &response); err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
|
||||
@@ -632,7 +632,7 @@ func (k *Kraken) GetClosedOrders(args GetClosedOrdersOptions) (ClosedOrders, err
|
||||
Result ClosedOrders `json:"result"`
|
||||
}
|
||||
|
||||
if err := k.SendAuthenticatedHTTPRequest(krakenClosedOrders, params, &response); err != nil {
|
||||
if err := k.SendAuthenticatedHTTPRequest(exchange.RestSpot, krakenClosedOrders, params, &response); err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
|
||||
@@ -662,7 +662,7 @@ func (k *Kraken) QueryOrdersInfo(args OrderInfoOptions, txid string, txids ...st
|
||||
Result map[string]OrderInfo `json:"result"`
|
||||
}
|
||||
|
||||
if err := k.SendAuthenticatedHTTPRequest(krakenQueryOrders, params, &response); err != nil {
|
||||
if err := k.SendAuthenticatedHTTPRequest(exchange.RestSpot, krakenQueryOrders, params, &response); err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
|
||||
@@ -700,7 +700,7 @@ func (k *Kraken) GetTradesHistory(args ...GetTradesHistoryOptions) (TradesHistor
|
||||
Result TradesHistory `json:"result"`
|
||||
}
|
||||
|
||||
if err := k.SendAuthenticatedHTTPRequest(krakenTradeHistory, params, &response); err != nil {
|
||||
if err := k.SendAuthenticatedHTTPRequest(exchange.RestSpot, krakenTradeHistory, params, &response); err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
|
||||
@@ -726,7 +726,7 @@ func (k *Kraken) QueryTrades(trades bool, txid string, txids ...string) (map[str
|
||||
Result map[string]TradeInfo `json:"result"`
|
||||
}
|
||||
|
||||
if err := k.SendAuthenticatedHTTPRequest(krakenQueryTrades, params, &response); err != nil {
|
||||
if err := k.SendAuthenticatedHTTPRequest(exchange.RestSpot, krakenQueryTrades, params, &response); err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
|
||||
@@ -750,7 +750,7 @@ func (k *Kraken) OpenPositions(docalcs bool, txids ...string) (map[string]Positi
|
||||
Result map[string]Position `json:"result"`
|
||||
}
|
||||
|
||||
if err := k.SendAuthenticatedHTTPRequest(krakenOpenPositions, params, &response); err != nil {
|
||||
if err := k.SendAuthenticatedHTTPRequest(exchange.RestSpot, krakenOpenPositions, params, &response); err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
|
||||
@@ -792,7 +792,7 @@ func (k *Kraken) GetLedgers(args ...GetLedgersOptions) (Ledgers, error) {
|
||||
Result Ledgers `json:"result"`
|
||||
}
|
||||
|
||||
if err := k.SendAuthenticatedHTTPRequest(krakenLedgers, params, &response); err != nil {
|
||||
if err := k.SendAuthenticatedHTTPRequest(exchange.RestSpot, krakenLedgers, params, &response); err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
|
||||
@@ -814,7 +814,7 @@ func (k *Kraken) QueryLedgers(id string, ids ...string) (map[string]LedgerInfo,
|
||||
Result map[string]LedgerInfo `json:"result"`
|
||||
}
|
||||
|
||||
if err := k.SendAuthenticatedHTTPRequest(krakenQueryLedgers, params, &response); err != nil {
|
||||
if err := k.SendAuthenticatedHTTPRequest(exchange.RestSpot, krakenQueryLedgers, params, &response); err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
|
||||
@@ -822,23 +822,29 @@ func (k *Kraken) QueryLedgers(id string, ids ...string) (map[string]LedgerInfo,
|
||||
}
|
||||
|
||||
// GetTradeVolume returns your trade volume by currency
|
||||
func (k *Kraken) GetTradeVolume(feeinfo bool, symbol ...string) (TradeVolumeResponse, error) {
|
||||
func (k *Kraken) GetTradeVolume(feeinfo bool, symbol ...currency.Pair) (TradeVolumeResponse, error) {
|
||||
var response struct {
|
||||
Error []string `json:"error"`
|
||||
Result TradeVolumeResponse `json:"result"`
|
||||
}
|
||||
params := url.Values{}
|
||||
|
||||
var formattedPairs []string
|
||||
for x := range symbol {
|
||||
symbolValue, err := k.FormatSymbol(symbol[x], asset.Spot)
|
||||
if err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
formattedPairs = append(formattedPairs, symbolValue)
|
||||
}
|
||||
if symbol != nil {
|
||||
params.Set("pair", strings.Join(symbol, ","))
|
||||
params.Set("pair", strings.Join(formattedPairs, ","))
|
||||
}
|
||||
|
||||
if feeinfo {
|
||||
params.Set("fee-info", "true")
|
||||
}
|
||||
|
||||
var response struct {
|
||||
Error []string `json:"error"`
|
||||
Result TradeVolumeResponse `json:"result"`
|
||||
}
|
||||
|
||||
if err := k.SendAuthenticatedHTTPRequest(krakenTradeVolume, params, &response); err != nil {
|
||||
if err := k.SendAuthenticatedHTTPRequest(exchange.RestSpot, krakenTradeVolume, params, &response); err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
|
||||
@@ -846,9 +852,17 @@ func (k *Kraken) GetTradeVolume(feeinfo bool, symbol ...string) (TradeVolumeResp
|
||||
}
|
||||
|
||||
// AddOrder adds a new order for Kraken exchange
|
||||
func (k *Kraken) AddOrder(symbol, side, orderType string, volume, price, price2, leverage float64, args *AddOrderOptions) (AddOrderResponse, error) {
|
||||
func (k *Kraken) AddOrder(symbol currency.Pair, side, orderType string, volume, price, price2, leverage float64, args *AddOrderOptions) (AddOrderResponse, error) {
|
||||
var response struct {
|
||||
Error []string `json:"error"`
|
||||
Result AddOrderResponse `json:"result"`
|
||||
}
|
||||
symbolValue, err := k.FormatSymbol(symbol, asset.Spot)
|
||||
if err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
params := url.Values{
|
||||
"pair": {symbol},
|
||||
"pair": {symbolValue},
|
||||
"type": {strings.ToLower(side)},
|
||||
"ordertype": {strings.ToLower(orderType)},
|
||||
"volume": {strconv.FormatFloat(volume, 'f', -1, 64)},
|
||||
@@ -894,12 +908,7 @@ func (k *Kraken) AddOrder(symbol, side, orderType string, volume, price, price2,
|
||||
params.Set("validate", "true")
|
||||
}
|
||||
|
||||
var response struct {
|
||||
Error []string `json:"error"`
|
||||
Result AddOrderResponse `json:"result"`
|
||||
}
|
||||
|
||||
if err := k.SendAuthenticatedHTTPRequest(krakenOrderPlace, params, &response); err != nil {
|
||||
if err := k.SendAuthenticatedHTTPRequest(exchange.RestSpot, krakenOrderPlace, params, &response); err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
|
||||
@@ -917,7 +926,7 @@ func (k *Kraken) CancelExistingOrder(txid string) (CancelOrderResponse, error) {
|
||||
Result CancelOrderResponse `json:"result"`
|
||||
}
|
||||
|
||||
if err := k.SendAuthenticatedHTTPRequest(krakenOrderCancel, values, &response); err != nil {
|
||||
if err := k.SendAuthenticatedHTTPRequest(exchange.RestSpot, krakenOrderCancel, values, &response); err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
|
||||
@@ -944,10 +953,14 @@ func GetError(apiErrors []string) error {
|
||||
}
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP requests
|
||||
func (k *Kraken) SendHTTPRequest(path string, result interface{}) error {
|
||||
func (k *Kraken) SendHTTPRequest(ep exchange.URL, path string, result interface{}) error {
|
||||
endpoint, err := k.API.Endpoints.GetURL(ep)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return k.SendPayload(context.Background(), &request.Item{
|
||||
Method: http.MethodGet,
|
||||
Path: path,
|
||||
Path: endpoint + path,
|
||||
Result: result,
|
||||
Verbose: k.Verbose,
|
||||
HTTPDebugging: k.HTTPDebugging,
|
||||
@@ -956,12 +969,15 @@ func (k *Kraken) SendHTTPRequest(path string, result interface{}) error {
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated HTTP request
|
||||
func (k *Kraken) SendAuthenticatedHTTPRequest(method string, params url.Values, result interface{}) (err error) {
|
||||
func (k *Kraken) SendAuthenticatedHTTPRequest(ep exchange.URL, method string, params url.Values, result interface{}) error {
|
||||
if !k.AllowAuthenticatedRequest() {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet,
|
||||
k.Name)
|
||||
}
|
||||
|
||||
endpoint, err := k.API.Endpoints.GetURL(ep)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path := fmt.Sprintf("/%s/private/%s", krakenAPIVersion, method)
|
||||
|
||||
params.Set("nonce", k.Requester.GetNonce(true).String())
|
||||
@@ -972,7 +988,7 @@ func (k *Kraken) SendAuthenticatedHTTPRequest(method string, params url.Values,
|
||||
|
||||
if k.Verbose {
|
||||
log.Debugf(log.ExchangeSys, "Sending POST request to %s, path: %s, params: %s",
|
||||
k.API.Endpoints.URL,
|
||||
endpoint,
|
||||
path,
|
||||
encoded)
|
||||
}
|
||||
@@ -981,40 +997,49 @@ func (k *Kraken) SendAuthenticatedHTTPRequest(method string, params url.Values,
|
||||
headers["API-Key"] = k.API.Credentials.Key
|
||||
headers["API-Sign"] = signature
|
||||
|
||||
return k.SendPayload(context.Background(), &request.Item{
|
||||
interim := json.RawMessage{}
|
||||
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Minute))
|
||||
defer cancel()
|
||||
err = k.SendPayload(ctx, &request.Item{
|
||||
Method: http.MethodPost,
|
||||
Path: k.API.Endpoints.URL + path,
|
||||
Path: endpoint + path,
|
||||
Headers: headers,
|
||||
Body: strings.NewReader(encoded),
|
||||
Result: result,
|
||||
Result: &interim,
|
||||
AuthRequest: true,
|
||||
NonceEnabled: true,
|
||||
Verbose: k.Verbose,
|
||||
HTTPDebugging: k.HTTPDebugging,
|
||||
HTTPRecording: k.HTTPRecording,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var errCap SpotAuthError
|
||||
if err := json.Unmarshal(interim, &errCap); err == nil {
|
||||
if len(errCap.Error) != 0 {
|
||||
return errors.New(errCap.Error[0])
|
||||
}
|
||||
}
|
||||
return json.Unmarshal(interim, result)
|
||||
}
|
||||
|
||||
// GetFee returns an estimate of fee based on type of transaction
|
||||
func (k *Kraken) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||||
var fee float64
|
||||
c := feeBuilder.Pair.Base.String() +
|
||||
feeBuilder.Pair.Delimiter +
|
||||
feeBuilder.Pair.Quote.String()
|
||||
|
||||
switch feeBuilder.FeeType {
|
||||
case exchange.CryptocurrencyTradeFee:
|
||||
feePair, err := k.GetTradeVolume(true, c)
|
||||
feePair, err := k.GetTradeVolume(true, feeBuilder.Pair)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if feeBuilder.IsMaker {
|
||||
fee = calculateTradingFee(c,
|
||||
fee = calculateTradingFee(feePair.Currency,
|
||||
feePair.FeesMaker,
|
||||
feeBuilder.PurchasePrice,
|
||||
feeBuilder.Amount)
|
||||
} else {
|
||||
fee = calculateTradingFee(c,
|
||||
fee = calculateTradingFee(feePair.Currency,
|
||||
feePair.Fees,
|
||||
feeBuilder.PurchasePrice,
|
||||
feeBuilder.Amount)
|
||||
@@ -1078,7 +1103,7 @@ func (k *Kraken) GetCryptoDepositAddress(method, code string) (string, error) {
|
||||
values.Set("asset", code)
|
||||
values.Set("method", method)
|
||||
|
||||
err := k.SendAuthenticatedHTTPRequest(krakenDepositAddresses, values, &resp)
|
||||
err := k.SendAuthenticatedHTTPRequest(exchange.RestSpot, krakenDepositAddresses, values, &resp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -1103,7 +1128,7 @@ func (k *Kraken) WithdrawStatus(c currency.Code, method string) ([]WithdrawStatu
|
||||
params.Set("method", method)
|
||||
}
|
||||
|
||||
if err := k.SendAuthenticatedHTTPRequest(krakenWithdrawStatus, params, &response); err != nil {
|
||||
if err := k.SendAuthenticatedHTTPRequest(exchange.RestSpot, krakenWithdrawStatus, params, &response); err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
|
||||
@@ -1121,7 +1146,7 @@ func (k *Kraken) WithdrawCancel(c currency.Code, refID string) (bool, error) {
|
||||
params.Set("asset", c.String())
|
||||
params.Set("refid", refID)
|
||||
|
||||
if err := k.SendAuthenticatedHTTPRequest(krakenWithdrawCancel, params, &response); err != nil {
|
||||
if err := k.SendAuthenticatedHTTPRequest(exchange.RestSpot, krakenWithdrawCancel, params, &response); err != nil {
|
||||
return response.Result, err
|
||||
}
|
||||
|
||||
@@ -1131,7 +1156,7 @@ func (k *Kraken) WithdrawCancel(c currency.Code, refID string) (bool, error) {
|
||||
// GetWebsocketToken returns a websocket token
|
||||
func (k *Kraken) GetWebsocketToken() (string, error) {
|
||||
var response WsTokenResponse
|
||||
if err := k.SendAuthenticatedHTTPRequest(krakenWebsocketToken, url.Values{}, &response); err != nil {
|
||||
if err := k.SendAuthenticatedHTTPRequest(exchange.RestSpot, krakenWebsocketToken, url.Values{}, &response); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(response.Error) > 0 {
|
||||
|
||||
307
exchanges/kraken/kraken_futures.go
Normal file
307
exchanges/kraken/kraken_futures.go
Normal file
@@ -0,0 +1,307 @@
|
||||
package kraken
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"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/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
|
||||
)
|
||||
|
||||
// GetFuturesOrderbook gets orderbook data for futures
|
||||
func (k *Kraken) GetFuturesOrderbook(symbol currency.Pair) (FuturesOrderbookData, error) {
|
||||
var resp FuturesOrderbookData
|
||||
params := url.Values{}
|
||||
symbolValue, err := k.FormatSymbol(symbol, asset.Futures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("symbol", symbolValue)
|
||||
return resp, k.SendHTTPRequest(exchange.RestFutures, futuresOrderbook+"?"+params.Encode(), &resp)
|
||||
}
|
||||
|
||||
// GetFuturesMarkets gets a list of futures markets and their data
|
||||
func (k *Kraken) GetFuturesMarkets() (FuturesInstrumentData, error) {
|
||||
var resp FuturesInstrumentData
|
||||
return resp, k.SendHTTPRequest(exchange.RestFutures, futuresInstruments, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesTickers gets a list of futures tickers and their data
|
||||
func (k *Kraken) GetFuturesTickers() (FuturesTickerData, error) {
|
||||
var resp FuturesTickerData
|
||||
return resp, k.SendHTTPRequest(exchange.RestFutures, futuresTickers, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesTradeHistory gets public trade history data for futures
|
||||
func (k *Kraken) GetFuturesTradeHistory(symbol currency.Pair, lastTime time.Time) (FuturesTradeHistoryData, error) {
|
||||
var resp FuturesTradeHistoryData
|
||||
params := url.Values{}
|
||||
symbolValue, err := k.FormatSymbol(symbol, asset.Futures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("symbol", symbolValue)
|
||||
if !lastTime.IsZero() {
|
||||
params.Set("lastTime", lastTime.Format("2006-01-02T15:04:05.070Z"))
|
||||
}
|
||||
return resp, k.SendHTTPRequest(exchange.RestFutures, futuresTradeHistory+"?"+params.Encode(), &resp)
|
||||
}
|
||||
|
||||
// FuturesBatchOrder places a batch order for futures
|
||||
func (k *Kraken) FuturesBatchOrder(data []PlaceBatchOrderData) (FuturesAccountsData, error) {
|
||||
var resp FuturesAccountsData
|
||||
for x := range data {
|
||||
unformattedPair, err := currency.NewPairFromString(data[x].Symbol)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
formattedPair, err := k.FormatExchangeCurrency(unformattedPair, asset.Futures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
data[x].Symbol = formattedPair.String()
|
||||
}
|
||||
req := make(map[string]interface{})
|
||||
req["batchOrder"] = data
|
||||
return resp, k.SendFuturesAuthRequest(http.MethodPost, futuresBatchOrder, nil, req, &resp)
|
||||
}
|
||||
|
||||
// FuturesEditOrder edits a futures order
|
||||
func (k *Kraken) FuturesEditOrder(orderID, clientOrderID string, size, limitPrice, stopPrice float64) (FuturesAccountsData, error) {
|
||||
var resp FuturesAccountsData
|
||||
params := url.Values{}
|
||||
if orderID != "" {
|
||||
params.Set("orderId", orderID)
|
||||
}
|
||||
if clientOrderID != "" {
|
||||
params.Set("cliOrderId", clientOrderID)
|
||||
}
|
||||
params.Set("size", strconv.FormatFloat(size, 'f', -1, 64))
|
||||
params.Set("limitPrice", strconv.FormatFloat(limitPrice, 'f', -1, 64))
|
||||
params.Set("stopPrice", strconv.FormatFloat(stopPrice, 'f', -1, 64))
|
||||
return resp, k.SendFuturesAuthRequest(http.MethodPost, futuresEditOrder, params, nil, &resp)
|
||||
}
|
||||
|
||||
// FuturesSendOrder sends a futures order
|
||||
func (k *Kraken) FuturesSendOrder(orderType order.Type, symbol currency.Pair, side, triggerSignal, clientOrderID, reduceOnly string,
|
||||
size, limitPrice, stopPrice float64) (FuturesSendOrderData, error) {
|
||||
var resp FuturesSendOrderData
|
||||
oType, ok := validOrderTypes[orderType]
|
||||
if !ok {
|
||||
return resp, errors.New("invalid orderType")
|
||||
}
|
||||
params := url.Values{}
|
||||
params.Set("orderType", oType)
|
||||
symbolValue, err := k.FormatSymbol(symbol, asset.Futures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("symbol", symbolValue)
|
||||
if !common.StringDataCompare(validSide, side) {
|
||||
return resp, errors.New("invalid side")
|
||||
}
|
||||
params.Set("side", side)
|
||||
if triggerSignal != "" {
|
||||
if !common.StringDataCompare(validTriggerSignal, triggerSignal) {
|
||||
return resp, errors.New("invalid triggerSignal")
|
||||
}
|
||||
params.Set("triggerSignal", triggerSignal)
|
||||
}
|
||||
if clientOrderID != "" {
|
||||
params.Set("cliOrdId", clientOrderID)
|
||||
}
|
||||
if reduceOnly != "" {
|
||||
if !common.StringDataCompare(validReduceOnly, reduceOnly) {
|
||||
return resp, errors.New("invalid reduceOnly")
|
||||
}
|
||||
params.Set("reduceOnly", reduceOnly)
|
||||
}
|
||||
params.Set("size", strconv.FormatFloat(size, 'f', -1, 64))
|
||||
params.Set("limitPrice", strconv.FormatFloat(limitPrice, 'f', -1, 64))
|
||||
if stopPrice != 0 {
|
||||
params.Set("stopPrice", strconv.FormatFloat(stopPrice, 'f', -1, 64))
|
||||
}
|
||||
return resp, k.SendFuturesAuthRequest(http.MethodPost, futuresSendOrder, params, nil, &resp)
|
||||
}
|
||||
|
||||
// FuturesCancelOrder cancels an order
|
||||
func (k *Kraken) FuturesCancelOrder(orderID, clientOrderID string) (FuturesCancelOrderData, error) {
|
||||
var resp FuturesCancelOrderData
|
||||
params := url.Values{}
|
||||
if orderID != "" {
|
||||
params.Set("order_id", orderID)
|
||||
}
|
||||
if clientOrderID != "" {
|
||||
params.Set("cliOrdId", clientOrderID)
|
||||
}
|
||||
return resp, k.SendFuturesAuthRequest(http.MethodPost, futuresCancelOrder, params, nil, &resp)
|
||||
}
|
||||
|
||||
// FuturesGetFills gets order fills for futures
|
||||
func (k *Kraken) FuturesGetFills(lastFillTime time.Time) (FuturesFillsData, error) {
|
||||
var resp FuturesFillsData
|
||||
params := url.Values{}
|
||||
if !lastFillTime.IsZero() {
|
||||
params.Set("lastFillTime", lastFillTime.UTC().Format("2006-01-02T15:04:05.999Z"))
|
||||
}
|
||||
return resp, k.SendFuturesAuthRequest(http.MethodGet, futuresOrderFills, params, nil, &resp)
|
||||
}
|
||||
|
||||
// FuturesTransfer transfers funds between accounts
|
||||
func (k *Kraken) FuturesTransfer(fromAccount, toAccount, unit string, amount float64) (FuturesTransferData, error) {
|
||||
var resp FuturesTransferData
|
||||
req := make(map[string]interface{})
|
||||
req["fromAccount"] = fromAccount
|
||||
req["toAccount"] = toAccount
|
||||
req["unit"] = unit
|
||||
req["amount"] = amount
|
||||
return resp, k.SendFuturesAuthRequest(http.MethodPost, futuresTransfer, nil, nil, &resp)
|
||||
}
|
||||
|
||||
// FuturesGetOpenPositions gets futures platform's notifications
|
||||
func (k *Kraken) FuturesGetOpenPositions() (FuturesOpenPositions, error) {
|
||||
var resp FuturesOpenPositions
|
||||
return resp, k.SendFuturesAuthRequest(http.MethodGet, futuresOpenPositions, nil, nil, &resp)
|
||||
}
|
||||
|
||||
// FuturesNotifications gets futures notifications
|
||||
func (k *Kraken) FuturesNotifications() (FuturesNotificationData, error) {
|
||||
var resp FuturesNotificationData
|
||||
return resp, k.SendFuturesAuthRequest(http.MethodGet, futuresNotifications, nil, nil, &resp)
|
||||
}
|
||||
|
||||
// FuturesCancelAllOrders cancels all futures orders for a given symbol or all symbols
|
||||
func (k *Kraken) FuturesCancelAllOrders(symbol currency.Pair) (CancelAllOrdersData, error) {
|
||||
var resp CancelAllOrdersData
|
||||
params := url.Values{}
|
||||
if symbol != (currency.Pair{}) {
|
||||
symbolValue, err := k.FormatSymbol(symbol, asset.Futures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("symbol", symbolValue)
|
||||
}
|
||||
return resp, k.SendFuturesAuthRequest(http.MethodPost, futuresCancelAllOrders, params, nil, &resp)
|
||||
}
|
||||
|
||||
// FuturesCancelAllOrdersAfter cancels all futures orders for all symbols after a period of time (timeout measured in seconds)
|
||||
func (k *Kraken) FuturesCancelAllOrdersAfter(timeout int64) (CancelOrdersAfterData, error) {
|
||||
var resp CancelOrdersAfterData
|
||||
params := url.Values{}
|
||||
params.Set("timeout", strconv.FormatInt(timeout, 10))
|
||||
return resp, k.SendFuturesAuthRequest(http.MethodPost, futuresCancelOrdersAfter, params, nil, &resp)
|
||||
}
|
||||
|
||||
// FuturesOpenOrders gets all futures open orders
|
||||
func (k *Kraken) FuturesOpenOrders() (FuturesOpenOrdersData, error) {
|
||||
var resp FuturesOpenOrdersData
|
||||
return resp, k.SendFuturesAuthRequest(http.MethodGet, futuresOpenOrders, nil, nil, &resp)
|
||||
}
|
||||
|
||||
// FuturesRecentOrders gets recent futures orders for a symbol or all symbols
|
||||
func (k *Kraken) FuturesRecentOrders(symbol currency.Pair) (FuturesRecentOrdersData, error) {
|
||||
var resp FuturesRecentOrdersData
|
||||
params := url.Values{}
|
||||
if symbol != (currency.Pair{}) {
|
||||
symbolValue, err := k.FormatSymbol(symbol, asset.Futures)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("symbol", symbolValue)
|
||||
}
|
||||
return resp, k.SendFuturesAuthRequest(http.MethodGet, futuresRecentOrders, nil, nil, &resp)
|
||||
}
|
||||
|
||||
// FuturesWithdrawToSpotWallet withdraws currencies from futures wallet to spot wallet
|
||||
func (k *Kraken) FuturesWithdrawToSpotWallet(currency string, amount float64) (GenericResponse, error) {
|
||||
var resp GenericResponse
|
||||
params := url.Values{}
|
||||
params.Set("currency", currency)
|
||||
params.Set("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
return resp, k.SendFuturesAuthRequest(http.MethodPost, futuresWithdraw, params, nil, &resp)
|
||||
}
|
||||
|
||||
// FuturesGetTransfers withdraws currencies from futures wallet to spot wallet
|
||||
func (k *Kraken) FuturesGetTransfers(lastTransferTime time.Time) (GenericResponse, error) {
|
||||
var resp GenericResponse
|
||||
params := url.Values{}
|
||||
if !lastTransferTime.IsZero() {
|
||||
params.Set("lastTransferTime", lastTransferTime.UTC().Format(time.RFC3339))
|
||||
}
|
||||
return resp, k.SendFuturesAuthRequest(http.MethodGet, futuresTransfers, params, nil, &resp)
|
||||
}
|
||||
|
||||
// GetFuturesAccountData gets account data for futures
|
||||
func (k *Kraken) GetFuturesAccountData() (FuturesAccountsData, error) {
|
||||
var resp FuturesAccountsData
|
||||
return resp, k.SendFuturesAuthRequest(http.MethodGet, futuresAccountData, nil, nil, &resp)
|
||||
}
|
||||
|
||||
func (k *Kraken) signFuturesRequest(endpoint, nonce, data string) string {
|
||||
message := data + nonce + endpoint
|
||||
hash := crypto.GetSHA256([]byte(message))
|
||||
hc := crypto.GetHMAC(crypto.HashSHA512, hash, []byte(k.API.Credentials.Secret))
|
||||
return base64.StdEncoding.EncodeToString(hc)
|
||||
}
|
||||
|
||||
// SendFuturesAuthRequest will send an auth req
|
||||
func (k *Kraken) SendFuturesAuthRequest(method, path string, postData url.Values, data map[string]interface{}, result interface{}) error {
|
||||
if !k.AllowAuthenticatedRequest() {
|
||||
return fmt.Errorf(exchange.WarningAuthenticatedRequestWithoutCredentialsSet,
|
||||
k.Name)
|
||||
}
|
||||
if postData == nil {
|
||||
postData = url.Values{}
|
||||
}
|
||||
nonce := strconv.FormatInt(time.Now().UnixNano()/1000000, 10)
|
||||
reqData := ""
|
||||
if len(data) > 0 {
|
||||
temp, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
postData.Add("json", string(temp))
|
||||
reqData = "json=" + string(temp)
|
||||
}
|
||||
sig := k.signFuturesRequest(path, nonce, reqData)
|
||||
headers := map[string]string{
|
||||
"APIKey": k.API.Credentials.Key,
|
||||
"Authent": sig,
|
||||
"Nonce": nonce,
|
||||
}
|
||||
interim := json.RawMessage{}
|
||||
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Minute))
|
||||
defer cancel()
|
||||
err := k.SendPayload(ctx, &request.Item{
|
||||
Method: method,
|
||||
Path: futuresURL + common.EncodeURLValues(path, postData),
|
||||
Headers: headers,
|
||||
Result: &interim,
|
||||
AuthRequest: true,
|
||||
Verbose: k.Verbose,
|
||||
HTTPDebugging: k.HTTPDebugging,
|
||||
HTTPRecording: k.HTTPRecording,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var errCap AuthErrorData
|
||||
if err := json.Unmarshal(interim, &errCap); err == nil {
|
||||
if errCap.Result != "success" && errCap.Error != "" {
|
||||
return errors.New(errCap.Error)
|
||||
}
|
||||
}
|
||||
return json.Unmarshal(interim, result)
|
||||
}
|
||||
@@ -49,7 +49,6 @@ func TestMain(m *testing.M) {
|
||||
krakenConfig.API.AuthenticatedSupport = true
|
||||
krakenConfig.API.Credentials.Key = apiKey
|
||||
krakenConfig.API.Credentials.Secret = apiSecret
|
||||
krakenConfig.API.Endpoints.WebsocketURL = k.API.Endpoints.WebsocketURL
|
||||
k.Websocket = sharedtestvalues.NewTestWebsocket()
|
||||
err = k.Setup(krakenConfig)
|
||||
if err != nil {
|
||||
@@ -67,6 +66,301 @@ func TestGetServerTime(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchTradablePairs(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := k.FetchTradablePairs(asset.Futures)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
sp, err := currency.NewPairFromString("XBTUSD")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = k.UpdateTicker(sp, asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
fp, err := currency.NewPairFromString("pi_xbtusd")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = k.UpdateTicker(fp, asset.Futures)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateOrderbook(t *testing.T) {
|
||||
t.Parallel()
|
||||
sp, err := currency.NewPairFromString("BTCEUR")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = k.UpdateOrderbook(sp, asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
fp, err := currency.NewPairFromString("pi_xbtusd")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = k.UpdateOrderbook(fp, asset.Futures)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateAccountInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("skipping test: api keys not set")
|
||||
}
|
||||
_, err := k.UpdateAccountInfo(asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWrapperGetOrderInfo(t *testing.T) {
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("skipping test: api keys not set")
|
||||
}
|
||||
t.Parallel()
|
||||
_, err := k.GetOrderInfo("123", currency.Pair{}, asset.Futures)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuturesBatchOrder(t *testing.T) {
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test: api keys not set or canManipulateRealOrders")
|
||||
}
|
||||
t.Parallel()
|
||||
var data []PlaceBatchOrderData
|
||||
var tempData PlaceBatchOrderData
|
||||
tempData.PlaceOrderType = "cancel"
|
||||
tempData.OrderID = "test123"
|
||||
tempData.Symbol = "pi_xbtusd"
|
||||
data = append(data, tempData)
|
||||
_, err := k.FuturesBatchOrder(data)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuturesEditOrder(t *testing.T) {
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test: api keys not set or canManipulateRealOrders")
|
||||
}
|
||||
t.Parallel()
|
||||
_, err := k.FuturesEditOrder("test123", "", 5.2, 1, 0)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuturesSendOrder(t *testing.T) {
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test: api keys not set or canManipulateRealOrders")
|
||||
}
|
||||
t.Parallel()
|
||||
cp, err := currency.NewPairFromString("PI_XBTUSD")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = k.FuturesSendOrder(order.Limit, cp, "buy", "", "", "", 1, 1, 0.9)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuturesCancelOrder(t *testing.T) {
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test: api keys not set or canManipulateRealOrders")
|
||||
}
|
||||
t.Parallel()
|
||||
_, err := k.FuturesCancelOrder("test123", "")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuturesGetFills(t *testing.T) {
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("skipping test: api keys not set")
|
||||
}
|
||||
t.Parallel()
|
||||
_, err := k.FuturesGetFills(time.Now().Add(-time.Hour * 24))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuturesTransfer(t *testing.T) {
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("skipping test: api keys not set")
|
||||
}
|
||||
t.Parallel()
|
||||
_, err := k.FuturesTransfer("cash", "futures", "btc", 2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuturesGetOpenPositions(t *testing.T) {
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("skipping test: api keys not set")
|
||||
}
|
||||
t.Parallel()
|
||||
_, err := k.FuturesGetOpenPositions()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuturesNotifications(t *testing.T) {
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("skipping test: api keys not set")
|
||||
}
|
||||
t.Parallel()
|
||||
_, err := k.FuturesNotifications()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuturesCancelAllOrders(t *testing.T) {
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test: api keys not set or canManipulateRealOrders")
|
||||
}
|
||||
t.Parallel()
|
||||
cp, err := currency.NewPairFromString("PI_XBTUSD")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = k.FuturesCancelAllOrders(cp)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFuturesAccountData(t *testing.T) {
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("skipping test: api keys not set")
|
||||
}
|
||||
t.Parallel()
|
||||
_, err := k.GetFuturesAccountData()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuturesCancelAllOrdersAfter(t *testing.T) {
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test: api keys not set or canManipulateRealOrders")
|
||||
}
|
||||
t.Parallel()
|
||||
_, err := k.FuturesCancelAllOrdersAfter(50)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuturesOpenOrders(t *testing.T) {
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("skipping test: api keys not set")
|
||||
}
|
||||
t.Parallel()
|
||||
_, err := k.FuturesOpenOrders()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuturesRecentOrders(t *testing.T) {
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("skipping test: api keys not set")
|
||||
}
|
||||
t.Parallel()
|
||||
cp, err := currency.NewPairFromString("PI_XBTUSD")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = k.FuturesRecentOrders(cp)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuturesWithdrawToSpotWallet(t *testing.T) {
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test: api keys not set or canManipulateRealOrders")
|
||||
}
|
||||
t.Parallel()
|
||||
_, err := k.FuturesWithdrawToSpotWallet("xbt", 5)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuturesGetTransfers(t *testing.T) {
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("skipping test: api keys not set")
|
||||
}
|
||||
t.Parallel()
|
||||
_, err := k.FuturesGetTransfers(time.Now().Add(-time.Hour * 24))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFuturesOrderbook(t *testing.T) {
|
||||
t.Parallel()
|
||||
cp, err := currency.NewPairFromString("FI_xbtusd_200925")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = k.GetFuturesOrderbook(cp)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFuturesMarkets(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := k.GetFuturesMarkets()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFuturesTickers(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := k.GetFuturesTickers()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFuturesTradeHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
cp, err := currency.NewPairFromString("pi_xbtusd")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = k.GetFuturesTradeHistory(cp, time.Now().Add(-time.Hour*24))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetAssets API endpoint test
|
||||
func TestGetAssets(t *testing.T) {
|
||||
t.Parallel()
|
||||
@@ -137,7 +431,19 @@ func TestLookupCurrency(t *testing.T) {
|
||||
// TestGetAssetPairs API endpoint test
|
||||
func TestGetAssetPairs(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := k.GetAssetPairs()
|
||||
_, err := k.GetAssetPairs([]string{}, "fees")
|
||||
if err != nil {
|
||||
t.Error("GetAssetPairs() error", err)
|
||||
}
|
||||
_, err = k.GetAssetPairs([]string{}, "leverage")
|
||||
if err != nil {
|
||||
t.Error("GetAssetPairs() error", err)
|
||||
}
|
||||
_, err = k.GetAssetPairs([]string{}, "margin")
|
||||
if err != nil {
|
||||
t.Error("GetAssetPairs() error", err)
|
||||
}
|
||||
_, err = k.GetAssetPairs([]string{}, "")
|
||||
if err != nil {
|
||||
t.Error("GetAssetPairs() error", err)
|
||||
}
|
||||
@@ -146,7 +452,11 @@ func TestGetAssetPairs(t *testing.T) {
|
||||
// TestGetTicker API endpoint test
|
||||
func TestGetTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := k.GetTicker("BCHEUR")
|
||||
cp, err := currency.NewPairFromString("BCHEUR")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = k.GetTicker(cp)
|
||||
if err != nil {
|
||||
t.Error("GetTicker() error", err)
|
||||
}
|
||||
@@ -164,7 +474,11 @@ func TestGetTickers(t *testing.T) {
|
||||
// TestGetOHLC API endpoint test
|
||||
func TestGetOHLC(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := k.GetOHLC("XXBTZUSD", "1440")
|
||||
cp, err := currency.NewPairFromString("XXBTZUSD")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = k.GetOHLC(cp, "1440")
|
||||
if err != nil {
|
||||
t.Error("GetOHLC() error", err)
|
||||
}
|
||||
@@ -173,7 +487,11 @@ func TestGetOHLC(t *testing.T) {
|
||||
// TestGetDepth API endpoint test
|
||||
func TestGetDepth(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := k.GetDepth("BCHEUR")
|
||||
cp, err := currency.NewPairFromString("BCHEUR")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = k.GetDepth(cp)
|
||||
if err != nil {
|
||||
t.Error("GetDepth() error", err)
|
||||
}
|
||||
@@ -182,12 +500,19 @@ func TestGetDepth(t *testing.T) {
|
||||
// TestGetTrades API endpoint test
|
||||
func TestGetTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := k.GetTrades("BCHEUR")
|
||||
cp, err := currency.NewPairFromString("BCHEUR")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = k.GetTrades(cp)
|
||||
if err != nil {
|
||||
t.Error("GetTrades() error", err)
|
||||
}
|
||||
|
||||
_, err = k.GetTrades("MADEUP")
|
||||
cp2, err := currency.NewPairFromString("MADEUP")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = k.GetTrades(cp2)
|
||||
if err == nil {
|
||||
t.Error("expected error")
|
||||
}
|
||||
@@ -196,7 +521,11 @@ func TestGetTrades(t *testing.T) {
|
||||
// TestGetSpread API endpoint test
|
||||
func TestGetSpread(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := k.GetSpread("BCHEUR")
|
||||
cp, err := currency.NewPairFromString("BCHEUR")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = k.GetSpread(cp)
|
||||
if err != nil {
|
||||
t.Error("GetSpread() error", err)
|
||||
}
|
||||
@@ -301,7 +630,11 @@ func TestQueryLedgers(t *testing.T) {
|
||||
// TestGetTradeVolume API endpoint test
|
||||
func TestGetTradeVolume(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := k.GetTradeVolume(true, "OAVY7T-MV5VK-KHDF5X")
|
||||
cp, err := currency.NewPairFromString("OAVY7T-MV5VK-KHDF5X")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = k.GetTradeVolume(true, cp)
|
||||
if err == nil {
|
||||
t.Error("GetTradeVolume() Expected error")
|
||||
}
|
||||
@@ -311,7 +644,11 @@ func TestGetTradeVolume(t *testing.T) {
|
||||
func TestAddOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
args := AddOrderOptions{OrderFlags: "fcib"}
|
||||
_, err := k.AddOrder("XXBTZUSD",
|
||||
cp, err := currency.NewPairFromString("XXBTZUSD")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = k.AddOrder(cp,
|
||||
order.Sell.Lower(), order.Limit.Lower(),
|
||||
0.00000001, 0, 0, 0, &args)
|
||||
if err == nil {
|
||||
@@ -447,22 +784,31 @@ func TestFormatWithdrawPermissions(t *testing.T) {
|
||||
|
||||
// TestGetActiveOrders wrapper test
|
||||
func TestGetActiveOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("skipping test: api keys not set")
|
||||
}
|
||||
pair, err := currency.NewPairFromString("LTC_USDT")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
var getOrdersRequest = order.GetOrdersRequest{
|
||||
Type: order.AnyType,
|
||||
Type: order.AnyType,
|
||||
AssetType: asset.Spot,
|
||||
Pairs: currency.Pairs{pair},
|
||||
}
|
||||
|
||||
_, err := k.GetActiveOrders(&getOrdersRequest)
|
||||
if areTestAPIKeysSet() && err != nil {
|
||||
t.Errorf("Could not get open orders: %s", err)
|
||||
} else if !areTestAPIKeysSet() && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
_, err = k.GetActiveOrders(&getOrdersRequest)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetOrderHistory wrapper test
|
||||
func TestGetOrderHistory(t *testing.T) {
|
||||
var getOrdersRequest = order.GetOrdersRequest{
|
||||
Type: order.AnyType,
|
||||
Type: order.AnyType,
|
||||
AssetType: asset.Spot,
|
||||
}
|
||||
|
||||
_, err := k.GetOrderHistory(&getOrdersRequest)
|
||||
@@ -594,18 +940,30 @@ func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
// TestGetAccountInfo wrapper test
|
||||
func TestGetAccountInfo(t *testing.T) {
|
||||
if areTestAPIKeysSet() {
|
||||
_, err := k.UpdateAccountInfo()
|
||||
_, err := k.UpdateAccountInfo(asset.Spot)
|
||||
if err != nil {
|
||||
// Spot and Futures have separate api keys. Please ensure that the correct one is provided
|
||||
t.Error("GetAccountInfo() error", err)
|
||||
}
|
||||
} else {
|
||||
_, err := k.UpdateAccountInfo()
|
||||
_, err := k.UpdateAccountInfo(asset.Spot)
|
||||
if err == nil {
|
||||
t.Error("GetAccountInfo() Expected error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateFuturesAccountInfo(t *testing.T) {
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys not set. Skipping the test")
|
||||
}
|
||||
_, err := k.UpdateAccountInfo(asset.Futures)
|
||||
if err != nil {
|
||||
// Spot and Futures have separate api keys. Please ensure that the correct one is provided
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestModifyOrder wrapper test
|
||||
func TestModifyOrder(t *testing.T) {
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
@@ -620,6 +978,7 @@ func TestModifyOrder(t *testing.T) {
|
||||
// TestWithdraw wrapper test
|
||||
func TestWithdraw(t *testing.T) {
|
||||
withdrawCryptoRequest := withdraw.Request{
|
||||
Exchange: k.Name,
|
||||
Crypto: withdraw.CryptoRequest{
|
||||
Address: core.BitcoinDonationAddress,
|
||||
},
|
||||
@@ -1335,7 +1694,7 @@ func TestWsOpenOrders(t *testing.T) {
|
||||
"cost": "0.00000",
|
||||
"descr": {
|
||||
"close": "",
|
||||
"leverage": "0:1",
|
||||
"leverage": "0.1",
|
||||
"order": "sell 10.00345345 XBT/USD @ limit 34.50000 with 0:1 leverage",
|
||||
"ordertype": "limit",
|
||||
"pair": "XBT/USD",
|
||||
@@ -1364,7 +1723,7 @@ func TestWsOpenOrders(t *testing.T) {
|
||||
"cost": "0.00000",
|
||||
"descr": {
|
||||
"close": "",
|
||||
"leverage": "0:1",
|
||||
"leverage": "0.1",
|
||||
"order": "sell 0.00000010 XBT/USD @ limit 5334.60000 with 0:1 leverage",
|
||||
"ordertype": "limit",
|
||||
"pair": "XBT/USD",
|
||||
@@ -1393,7 +1752,7 @@ func TestWsOpenOrders(t *testing.T) {
|
||||
"cost": "0.00000",
|
||||
"descr": {
|
||||
"close": "",
|
||||
"leverage": "0:1",
|
||||
"leverage": "0.1",
|
||||
"order": "sell 0.00001000 XBT/USD @ limit 90.40000 with 0:1 leverage",
|
||||
"ordertype": "limit",
|
||||
"pair": "XBT/USD",
|
||||
@@ -1422,7 +1781,7 @@ func TestWsOpenOrders(t *testing.T) {
|
||||
"cost": "0.00000",
|
||||
"descr": {
|
||||
"close": "",
|
||||
"leverage": "0:1",
|
||||
"leverage": "0.1",
|
||||
"order": "sell 0.00001000 XBT/USD @ limit 9.00000 with 0:1 leverage",
|
||||
"ordertype": "limit",
|
||||
"pair": "XBT/USD",
|
||||
|
||||
@@ -1,22 +1,96 @@
|
||||
package kraken
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/stream"
|
||||
)
|
||||
|
||||
type assetTranslatorStore struct {
|
||||
l sync.RWMutex
|
||||
Assets map[string]string
|
||||
const (
|
||||
krakenAPIVersion = "0"
|
||||
krakenServerTime = "Time"
|
||||
krakenAssets = "Assets"
|
||||
krakenAssetPairs = "AssetPairs?"
|
||||
krakenTicker = "Ticker"
|
||||
krakenOHLC = "OHLC"
|
||||
krakenDepth = "Depth"
|
||||
krakenTrades = "Trades"
|
||||
krakenSpread = "Spread"
|
||||
krakenBalance = "Balance"
|
||||
krakenTradeBalance = "TradeBalance"
|
||||
krakenOpenOrders = "OpenOrders"
|
||||
krakenClosedOrders = "ClosedOrders"
|
||||
krakenQueryOrders = "QueryOrders"
|
||||
krakenTradeHistory = "TradesHistory"
|
||||
krakenQueryTrades = "QueryTrades"
|
||||
krakenOpenPositions = "OpenPositions"
|
||||
krakenLedgers = "Ledgers"
|
||||
krakenQueryLedgers = "QueryLedgers"
|
||||
krakenTradeVolume = "TradeVolume"
|
||||
krakenOrderCancel = "CancelOrder"
|
||||
krakenOrderPlace = "AddOrder"
|
||||
krakenWithdrawInfo = "WithdrawInfo"
|
||||
krakenWithdraw = "Withdraw"
|
||||
krakenDepositMethods = "DepositMethods"
|
||||
krakenDepositAddresses = "DepositAddresses"
|
||||
krakenWithdrawStatus = "WithdrawStatus"
|
||||
krakenWithdrawCancel = "WithdrawCancel"
|
||||
krakenWebsocketToken = "GetWebSocketsToken"
|
||||
|
||||
// Futures
|
||||
futuresTickers = "/api/v3/tickers"
|
||||
futuresOrderbook = "/api/v3/orderbook"
|
||||
futuresInstruments = "/api/v3/instruments"
|
||||
futuresTradeHistory = "/api/v3/history"
|
||||
|
||||
futuresSendOrder = "/api/v3/sendorder"
|
||||
futuresCancelOrder = "/api/v3/cancelorder"
|
||||
futuresOrderFills = "/api/v3/fills"
|
||||
futuresTransfer = "/api/v3/transfer"
|
||||
futuresOpenPositions = "/api/v3/openpositions"
|
||||
futuresBatchOrder = "/api/v3/batchorder"
|
||||
futuresNotifications = "/api/v3/notifications"
|
||||
futuresAccountData = "/api/v3/accounts"
|
||||
futuresCancelAllOrders = "/api/v3/cancelallorders"
|
||||
futuresCancelOrdersAfter = "/api/v3/cancelallordersafter"
|
||||
futuresOpenOrders = "/api/v3/openorders"
|
||||
futuresRecentOrders = "/api/v3/recentorders"
|
||||
futuresWithdraw = "/api/v3/withdrawal"
|
||||
futuresTransfers = "/api/v3/transfers"
|
||||
futuresEditOrder = "/api/v3/editorder"
|
||||
|
||||
// Rate limit consts
|
||||
krakenRateInterval = time.Second
|
||||
krakenRequestRate = 1
|
||||
|
||||
// Status consts
|
||||
statusOpen = "open"
|
||||
|
||||
krakenFormat = "2006-01-02T15:04:05.000Z"
|
||||
)
|
||||
|
||||
var (
|
||||
assetTranslator assetTranslatorStore
|
||||
)
|
||||
|
||||
// GenericResponse stores general response data for functions that only return success
|
||||
type GenericResponse struct {
|
||||
Timestamp string `json:"timestamp"`
|
||||
Result string `json:"result"`
|
||||
}
|
||||
|
||||
// TimeResponse type
|
||||
type TimeResponse struct {
|
||||
Unixtime int64 `json:"unixtime"`
|
||||
Rfc1123 string `json:"rfc1123"`
|
||||
// AuthErrorData stores authenticated error messages
|
||||
type AuthErrorData struct {
|
||||
Result string `json:"result"`
|
||||
ServerTime string `json:"serverTime"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
// SpotAuthError stores authenticated error messages
|
||||
type SpotAuthError struct {
|
||||
Error []string `json:"error"`
|
||||
}
|
||||
|
||||
// Asset holds asset information
|
||||
@@ -30,6 +104,7 @@ type Asset struct {
|
||||
// AssetPairs holds asset pair information
|
||||
type AssetPairs struct {
|
||||
Altname string `json:"altname"`
|
||||
Wsname string `json:"wsname"`
|
||||
AclassBase string `json:"aclass_base"`
|
||||
Base string `json:"base"`
|
||||
AclassQuote string `json:"aclass_quote"`
|
||||
@@ -45,6 +120,7 @@ type AssetPairs struct {
|
||||
FeeVolumeCurrency string `json:"fee_volume_currency"`
|
||||
MarginCall int `json:"margin_call"`
|
||||
MarginStop int `json:"margin_stop"`
|
||||
Ordermin string `json:"ordermin"`
|
||||
}
|
||||
|
||||
// Ticker is a standard ticker type
|
||||
@@ -520,7 +596,7 @@ type WsOpenOrder struct {
|
||||
Close string `json:"close"`
|
||||
Price float64 `json:"price,string"`
|
||||
Price2 float64 `json:"price2,string"`
|
||||
Leverage string `json:"leverage"`
|
||||
Leverage float64 `json:"leverage,string"`
|
||||
Order string `json:"order"`
|
||||
OrderType string `json:"ordertype"`
|
||||
Pair string `json:"pair"`
|
||||
@@ -623,3 +699,11 @@ type WsCancelOrderResponse struct {
|
||||
RequestID int64 `json:"reqid"`
|
||||
Count int64 `json:"count"`
|
||||
}
|
||||
|
||||
// OrderVars stores side, status and type for any order/trade
|
||||
type OrderVars struct {
|
||||
Side order.Side
|
||||
Status order.Status
|
||||
OrderType order.Type
|
||||
Fee float64
|
||||
}
|
||||
|
||||
@@ -599,7 +599,7 @@ func (k *Kraken) wsProcessOpenOrders(ownOrders interface{}) error {
|
||||
// allowing correlation between subscriptions and returned data
|
||||
func (k *Kraken) addNewSubscriptionChannelData(response *wsSubscription) {
|
||||
// We change the / to - to maintain compatibility with REST/config
|
||||
var pair currency.Pair
|
||||
var pair, fPair currency.Pair
|
||||
if response.Pair != "" {
|
||||
var err error
|
||||
pair, err = currency.NewPairFromString(response.Pair)
|
||||
@@ -607,11 +607,15 @@ func (k *Kraken) addNewSubscriptionChannelData(response *wsSubscription) {
|
||||
log.Errorf(log.ExchangeSys, "%s exchange error: %s", k.Name, err)
|
||||
return
|
||||
}
|
||||
pair.Delimiter = k.CurrencyPairs.RequestFormat.Delimiter
|
||||
fPair, err = k.FormatExchangeCurrency(pair, asset.Spot)
|
||||
if err != nil {
|
||||
log.Errorf(log.ExchangeSys, "%s exchange error: %s", k.Name, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
subscriptionChannelPair = append(subscriptionChannelPair, WebsocketChannelData{
|
||||
Subscription: response.Subscription.Name,
|
||||
Pair: pair,
|
||||
Pair: fPair,
|
||||
ChannelID: response.ChannelID,
|
||||
})
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user