mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 15:09:42 +00:00
Alphapoint: Remove exchange implementation (#1956)
* Initial plan * Initial analysis: Plan to remove Alphapoint exchange implementation Co-authored-by: thrasher- <4685270+thrasher-@users.noreply.github.com> * Remove Alphapoint exchange implementation and all references Co-authored-by: thrasher- <4685270+thrasher-@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: thrasher- <4685270+thrasher-@users.noreply.github.com>
This commit is contained in:
@@ -18,7 +18,6 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
|
||||
|
||||
| Exchange | REST API | Streaming API | FIX API |
|
||||
|----------|------|-----------|-----|
|
||||
| Alphapoint | Yes | Yes | NA |
|
||||
| Binance.US| Yes | Yes | NA |
|
||||
| Binance| Yes | Yes | NA |
|
||||
| Bitfinex | Yes | Yes | NA |
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
{{define "exchanges alphapoint" -}}
|
||||
{{template "header" .}}
|
||||
## Alphapoint Exchange
|
||||
|
||||
+ Please visit [Alphapoint](https://www.alphapoint.com/) for more info.
|
||||
|
||||
### How to enable
|
||||
|
||||
+ Not currently configurable
|
||||
|
||||
### Please click GoDocs chevron above to view current GoDoc information for this package
|
||||
{{template "contributions"}}
|
||||
{{template "donations" .}}
|
||||
{{end}}
|
||||
@@ -41,7 +41,6 @@ _b in this context is an `IBotExchange` implemented struct_
|
||||
|
||||
| Exchange | Recent Trades via REST | Live trade updates via Websocket | Trade history via REST |
|
||||
|----------|------|-----------|-----|
|
||||
| Alphapoint | No | No | No |
|
||||
| Binance.US | Yes | Yes | NA |
|
||||
| Binance| Yes | Yes | Yes |
|
||||
| Bitfinex | Yes | Yes | Yes |
|
||||
|
||||
@@ -19,7 +19,6 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
|
||||
|
||||
| Exchange | REST API | Streaming API | FIX API |
|
||||
|----------|------|-----------|-----|
|
||||
| Alphapoint | Yes | Yes | NA |
|
||||
| Binance.US| Yes | Yes | NA |
|
||||
| Binance| Yes | Yes | NA |
|
||||
| Bitfinex | Yes | Yes | NA |
|
||||
|
||||
@@ -607,7 +607,6 @@ var unsupportedAssets = []asset.Item{
|
||||
|
||||
var unsupportedExchangeNames = []string{
|
||||
"testexch",
|
||||
"alphapoint",
|
||||
"bitflyer", // Bitflyer has many "ErrNotYetImplemented, which is true, but not what we care to test for here
|
||||
"btse", // TODO rm once timeout issues resolved
|
||||
"poloniex", // outdated API // TODO rm once updated
|
||||
|
||||
@@ -132,7 +132,6 @@ Yes means supported, No means not yet implemented and NA means protocol unsuppor
|
||||
```go
|
||||
| Exchange | REST API | Streaming API | FIX API |
|
||||
|----------|------|-----------|-----|
|
||||
| Alphapoint | Yes | Yes | NA |
|
||||
| Binance| Yes | Yes | NA | // <-------- new exchange
|
||||
| Bitfinex | Yes | Yes | NA |
|
||||
| Bitflyer | Yes | No | NA |
|
||||
|
||||
@@ -42,7 +42,6 @@ $ ./gctcli withdrawcryptofunds --exchange=binance --currency=USDT --address=TJU9
|
||||
|
||||
| Exchange | Deposits | Withdrawals | Notes|
|
||||
|----------|----------|-------------|------|
|
||||
| Alphapoint | No | No | |
|
||||
| Binance.US | Yes | Yes | |
|
||||
| Binance | Yes | Yes | |
|
||||
| Bitfinex | Yes | Yes | Only supports USDT |
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
# GoCryptoTrader package Alphapoint
|
||||
|
||||
<img src="/common/gctlogo.png?raw=true" width="350px" height="350px" hspace="70">
|
||||
|
||||
|
||||
[](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml)
|
||||
[](https://github.com/thrasher-corp/gocryptotrader/blob/master/LICENSE)
|
||||
[](https://godoc.org/github.com/thrasher-corp/gocryptotrader/exchanges/alphapoint)
|
||||
[](https://codecov.io/gh/thrasher-corp/gocryptotrader)
|
||||
[](https://goreportcard.com/report/github.com/thrasher-corp/gocryptotrader)
|
||||
|
||||
|
||||
This alphapoint package is part of the GoCryptoTrader codebase.
|
||||
|
||||
## This is still in active development
|
||||
|
||||
You can track ideas, planned features and what's in progress on our [GoCryptoTrader Kanban board](https://github.com/orgs/thrasher-corp/projects/3).
|
||||
|
||||
Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://join.slack.com/t/gocryptotrader/shared_invite/zt-38z8abs3l-gH8AAOk8XND6DP5NfCiG_g)
|
||||
|
||||
## Alphapoint Exchange
|
||||
|
||||
+ Please visit [Alphapoint](https://www.alphapoint.com/) for more info.
|
||||
|
||||
### How to enable
|
||||
|
||||
+ Not currently configurable
|
||||
|
||||
### Please click GoDocs chevron above to view current GoDoc information for this package
|
||||
|
||||
## Contribution
|
||||
|
||||
Please feel free to submit any pull requests or suggest any desired features to be added.
|
||||
|
||||
When submitting a PR, please abide by our coding guidelines:
|
||||
|
||||
+ Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
|
||||
+ Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
|
||||
+ Code must adhere to our [coding style](https://github.com/thrasher-corp/gocryptotrader/blob/master/doc/coding_style.md).
|
||||
+ Pull requests need to be based on and opened against the `master` branch.
|
||||
|
||||
## Donations
|
||||
|
||||
<img src="https://github.com/thrasher-corp/gocryptotrader/blob/master/web/src/assets/donate.png?raw=true" hspace="70">
|
||||
|
||||
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
|
||||
|
||||
***bc1qk0jareu4jytc0cfrhr5wgshsq8282awpavfahc***
|
||||
@@ -1,598 +0,0 @@
|
||||
package alphapoint
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
gws "github.com/gorilla/websocket"
|
||||
"github.com/thrasher-corp/gocryptotrader/common/crypto"
|
||||
"github.com/thrasher-corp/gocryptotrader/encoding/json"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/nonce"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
|
||||
)
|
||||
|
||||
const (
|
||||
alphapointDefaultAPIURL = "https://sim3.alphapoint.com:8400"
|
||||
alphapointAPIVersion = "1"
|
||||
alphapointTicker = "GetTicker"
|
||||
alphapointTrades = "GetTrades"
|
||||
alphapointTradesByDate = "GetTradesByDate"
|
||||
alphapointOrderbook = "GetOrderBook"
|
||||
alphapointProductPairs = "GetProductPairs"
|
||||
alphapointProducts = "GetProducts"
|
||||
alphapointCreateAccount = "CreateAccount"
|
||||
alphapointUserInfo = "GetUserInfo"
|
||||
alphapointAccountInfo = "GetAccountInfo"
|
||||
alphapointAccountTrades = "GetAccountTrades"
|
||||
alphapointDepositAddresses = "GetDepositAddresses"
|
||||
alphapointWithdraw = "Withdraw"
|
||||
alphapointCreateOrder = "CreateOrder"
|
||||
alphapointModifyOrder = "ModifyOrder"
|
||||
alphapointCancelOrder = "CancelOrder"
|
||||
alphapointCancelAllOrders = "CancelAllOrders"
|
||||
alphapointOpenOrders = "GetAccountOpenOrders"
|
||||
alphapointOrderFee = "GetOrderFee"
|
||||
)
|
||||
|
||||
// Exchange implements exchange.IBotExchange and contains additional specific api methods for interacting with Alphapoint
|
||||
type Exchange struct {
|
||||
exchange.Base
|
||||
WebsocketConn *gws.Conn
|
||||
}
|
||||
|
||||
// GetTicker returns current ticker information from Alphapoint for a selected
|
||||
// currency pair ie "BTCUSD"
|
||||
func (e *Exchange) GetTicker(ctx context.Context, currencyPair string) (Ticker, error) {
|
||||
req := make(map[string]any)
|
||||
req["productPair"] = currencyPair
|
||||
response := Ticker{}
|
||||
|
||||
err := e.SendHTTPRequest(ctx,
|
||||
exchange.RestSpot,
|
||||
http.MethodPost,
|
||||
alphapointTicker,
|
||||
req,
|
||||
&response)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
if !response.IsAccepted {
|
||||
return response, errors.New(response.RejectReason)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// GetTrades fetches past trades for the given currency pair
|
||||
// currencyPair: ie "BTCUSD"
|
||||
// StartIndex: specifies the index to begin from, -1 being the first trade on
|
||||
// AlphaPoint Exchange. To begin from the most recent trade, set startIndex to
|
||||
// 0 (default: 0)
|
||||
// Count: specifies the number of trades to return (default: 10)
|
||||
func (e *Exchange) GetTrades(ctx context.Context, currencyPair string, startIndex, count int) (Trades, error) {
|
||||
req := make(map[string]any)
|
||||
req["ins"] = currencyPair
|
||||
req["startIndex"] = startIndex
|
||||
req["Count"] = count
|
||||
response := Trades{}
|
||||
|
||||
err := e.SendHTTPRequest(ctx,
|
||||
exchange.RestSpot, http.MethodPost, alphapointTrades, req, &response)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
if !response.IsAccepted {
|
||||
return response, errors.New(response.RejectReason)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// GetOrderbook fetches the current orderbook for a given currency pair
|
||||
// CurrencyPair - trade pair (ex: “BTCUSD”)
|
||||
func (e *Exchange) GetOrderbook(ctx context.Context, currencyPair string) (Orderbook, error) {
|
||||
req := make(map[string]any)
|
||||
req["productPair"] = currencyPair
|
||||
response := Orderbook{}
|
||||
|
||||
err := e.SendHTTPRequest(ctx,
|
||||
exchange.RestSpot, http.MethodPost, alphapointOrderbook, req, &response)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
if !response.IsAccepted {
|
||||
return response, errors.New(response.RejectReason)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// GetProductPairs gets the currency pairs currently traded on alphapoint
|
||||
func (e *Exchange) GetProductPairs(ctx context.Context) (ProductPairs, error) {
|
||||
response := ProductPairs{}
|
||||
|
||||
err := e.SendHTTPRequest(ctx,
|
||||
exchange.RestSpot, http.MethodPost, alphapointProductPairs, nil, &response)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
if !response.IsAccepted {
|
||||
return response, errors.New(response.RejectReason)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// GetProducts gets the currency products currently supported on alphapoint
|
||||
func (e *Exchange) GetProducts(ctx context.Context) (Products, error) {
|
||||
response := Products{}
|
||||
|
||||
err := e.SendHTTPRequest(ctx,
|
||||
exchange.RestSpot, http.MethodPost, alphapointProducts, nil, &response)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
if !response.IsAccepted {
|
||||
return response, errors.New(response.RejectReason)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// CreateAccount creates a new account on alphapoint
|
||||
// FirstName - First name
|
||||
// LastName - Last name
|
||||
// Email - Email address
|
||||
// Phone - Phone number (ex: “+12223334444”)
|
||||
// Password - Minimum 8 characters
|
||||
func (e *Exchange) CreateAccount(ctx context.Context, firstName, lastName, email, phone, password string) error {
|
||||
if len(password) < 8 {
|
||||
return errors.New(
|
||||
"alphapoint Error - Create account - Password must be 8 characters or more",
|
||||
)
|
||||
}
|
||||
|
||||
req := make(map[string]any)
|
||||
req["firstname"] = firstName
|
||||
req["lastname"] = lastName
|
||||
req["email"] = email
|
||||
req["phone"] = phone
|
||||
req["password"] = password
|
||||
response := Response{}
|
||||
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx,
|
||||
exchange.RestSpot, http.MethodPost, alphapointCreateAccount, req, &response)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create account. Reason: %s", err)
|
||||
}
|
||||
if !response.IsAccepted {
|
||||
return errors.New(response.RejectReason)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetUserInfo returns current account user information
|
||||
func (e *Exchange) GetUserInfo(ctx context.Context) (UserInfo, error) {
|
||||
response := UserInfo{}
|
||||
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx,
|
||||
exchange.RestSpot,
|
||||
http.MethodPost,
|
||||
alphapointUserInfo,
|
||||
map[string]any{},
|
||||
&response)
|
||||
if err != nil {
|
||||
return UserInfo{}, err
|
||||
}
|
||||
if !response.IsAccepted {
|
||||
return response, errors.New(response.RejectReason)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// SetUserInfo changes user name and/or 2FA settings
|
||||
// userInfoKVP - An array of key value pairs
|
||||
// FirstName - First name
|
||||
// LastName - Last name
|
||||
// UseAuthy2FA - “true” or “false” toggle Authy app
|
||||
// Cell2FACountryCode - Cell country code (ex: 1), required for Authentication
|
||||
// Cell2FAValue - Cell phone number, required for Authentication
|
||||
// Use2FAForWithdraw - “true” or “false” set to true for using 2FA for
|
||||
// withdrawals
|
||||
func (e *Exchange) SetUserInfo(ctx context.Context, firstName, lastName, cell2FACountryCode, cell2FAValue string, useAuthy2FA, use2FAForWithdraw bool) (UserInfoSet, error) {
|
||||
response := UserInfoSet{}
|
||||
|
||||
userInfoKVPs := []UserInfoKVP{
|
||||
{
|
||||
Key: "FirstName",
|
||||
Value: firstName,
|
||||
},
|
||||
{
|
||||
Key: "LastName",
|
||||
Value: lastName,
|
||||
},
|
||||
{
|
||||
Key: "Cell2FACountryCode",
|
||||
Value: cell2FACountryCode,
|
||||
},
|
||||
{
|
||||
Key: "Cell2FAValue",
|
||||
Value: cell2FAValue,
|
||||
},
|
||||
{
|
||||
Key: "UseAuthy2FA",
|
||||
Value: strconv.FormatBool(useAuthy2FA),
|
||||
},
|
||||
{
|
||||
Key: "Use2FAForWithdraw",
|
||||
Value: strconv.FormatBool(use2FAForWithdraw),
|
||||
},
|
||||
}
|
||||
|
||||
req := make(map[string]any)
|
||||
req["userInfoKVP"] = userInfoKVPs
|
||||
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx,
|
||||
exchange.RestSpot,
|
||||
http.MethodPost,
|
||||
alphapointUserInfo,
|
||||
req,
|
||||
&response,
|
||||
)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
if response.IsAccepted != "true" {
|
||||
return response, errors.New(response.RejectReason)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// GetAccountInformation returns account info
|
||||
func (e *Exchange) GetAccountInformation(ctx context.Context) (AccountInfo, error) {
|
||||
response := AccountInfo{}
|
||||
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx,
|
||||
exchange.RestSpot,
|
||||
http.MethodPost,
|
||||
alphapointAccountInfo,
|
||||
map[string]any{},
|
||||
&response,
|
||||
)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
if !response.IsAccepted {
|
||||
return response, errors.New(response.RejectReason)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// GetAccountTrades returns the trades executed on the account.
|
||||
// CurrencyPair - Instrument code (ex: “BTCUSD”)
|
||||
// StartIndex - Starting index, if less than 0 then start from the beginning
|
||||
// Count - Returns last trade, (Default: 30)
|
||||
func (e *Exchange) GetAccountTrades(ctx context.Context, currencyPair string, startIndex, count int) (Trades, error) {
|
||||
req := make(map[string]any)
|
||||
req["ins"] = currencyPair
|
||||
req["startIndex"] = startIndex
|
||||
req["count"] = count
|
||||
response := Trades{}
|
||||
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx,
|
||||
exchange.RestSpot,
|
||||
http.MethodPost,
|
||||
alphapointAccountTrades,
|
||||
req,
|
||||
&response,
|
||||
)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
if !response.IsAccepted {
|
||||
return response, errors.New(response.RejectReason)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// GetDepositAddresses generates a deposit address
|
||||
func (e *Exchange) GetDepositAddresses(ctx context.Context) ([]DepositAddresses, error) {
|
||||
response := Response{}
|
||||
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx,
|
||||
exchange.RestSpot,
|
||||
http.MethodPost,
|
||||
alphapointDepositAddresses,
|
||||
map[string]any{},
|
||||
&response,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !response.IsAccepted {
|
||||
return nil, errors.New(response.RejectReason)
|
||||
}
|
||||
return response.Addresses, nil
|
||||
}
|
||||
|
||||
// WithdrawCoins withdraws a coin to a specific address
|
||||
// symbol - Instrument name (ex: “BTCUSD”)
|
||||
// product - Currency name (ex: “BTC”)
|
||||
// amount - Amount (ex: “.011”)
|
||||
// address - Withdraw address
|
||||
func (e *Exchange) WithdrawCoins(ctx context.Context, symbol, product, address string, amount float64) error {
|
||||
req := make(map[string]any)
|
||||
req["ins"] = symbol
|
||||
req["product"] = product
|
||||
req["amount"] = strconv.FormatFloat(amount, 'f', -1, 64)
|
||||
req["sendToAddress"] = address
|
||||
|
||||
response := Response{}
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx,
|
||||
exchange.RestSpot,
|
||||
http.MethodPost,
|
||||
alphapointWithdraw,
|
||||
req,
|
||||
&response,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !response.IsAccepted {
|
||||
return errors.New(response.RejectReason)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Exchange) convertOrderTypeToOrderTypeNumber(orderType string) (orderTypeNumber int64) {
|
||||
if orderType == order.Market.String() {
|
||||
orderTypeNumber = 1
|
||||
}
|
||||
|
||||
return orderTypeNumber
|
||||
}
|
||||
|
||||
// CreateOrder creates a market or limit order
|
||||
// symbol - Instrument code (ex: “BTCUSD”)
|
||||
// side - “buy” or “sell”
|
||||
// orderType - “1” for market orders, “0” for limit orders
|
||||
// quantity - Quantity
|
||||
// price - Price in USD
|
||||
func (e *Exchange) CreateOrder(ctx context.Context, symbol, side, orderType string, quantity, price float64) (int64, error) {
|
||||
orderTypeNumber := e.convertOrderTypeToOrderTypeNumber(orderType)
|
||||
req := make(map[string]any)
|
||||
req["ins"] = symbol
|
||||
req["side"] = side
|
||||
req["orderType"] = orderTypeNumber
|
||||
req["qty"] = strconv.FormatFloat(quantity, 'f', -1, 64)
|
||||
req["px"] = strconv.FormatFloat(price, 'f', -1, 64)
|
||||
response := Response{}
|
||||
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx,
|
||||
exchange.RestSpot,
|
||||
http.MethodPost,
|
||||
alphapointCreateOrder,
|
||||
req,
|
||||
&response,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if !response.IsAccepted {
|
||||
return 0, errors.New(response.RejectReason)
|
||||
}
|
||||
return response.ServerOrderID, nil
|
||||
}
|
||||
|
||||
// ModifyExistingOrder modifies and existing Order
|
||||
// OrderID - tracked order id number
|
||||
// symbol - Instrument code (ex: “BTCUSD”)
|
||||
// modifyAction - “0” or “1”
|
||||
// “0” means "Move to top", which will modify the order price to the top of the
|
||||
// book. A buy order will be modified to the highest bid and a sell order will
|
||||
// be modified to the lowest ask price. “1” means "Execute now", which will
|
||||
// convert a limit order into a market order.
|
||||
func (e *Exchange) ModifyExistingOrder(ctx context.Context, symbol string, orderID, action int64) (int64, error) {
|
||||
req := make(map[string]any)
|
||||
req["ins"] = symbol
|
||||
req["serverOrderId"] = orderID
|
||||
req["modifyAction"] = action
|
||||
response := Response{}
|
||||
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx,
|
||||
exchange.RestSpot,
|
||||
http.MethodPost,
|
||||
alphapointModifyOrder,
|
||||
req,
|
||||
&response,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if !response.IsAccepted {
|
||||
return 0, errors.New(response.RejectReason)
|
||||
}
|
||||
return response.ModifyOrderID, nil
|
||||
}
|
||||
|
||||
// CancelExistingOrder cancels an order that has not been executed.
|
||||
// symbol - Instrument code (ex: “BTCUSD”)
|
||||
// OrderID - Order id (ex: 1000)
|
||||
func (e *Exchange) CancelExistingOrder(ctx context.Context, orderID int64, omsid string) (int64, error) {
|
||||
req := make(map[string]any)
|
||||
req["OrderId"] = orderID
|
||||
req["OMSId"] = omsid
|
||||
response := Response{}
|
||||
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx,
|
||||
exchange.RestSpot,
|
||||
http.MethodPost,
|
||||
alphapointCancelOrder,
|
||||
req,
|
||||
&response,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if !response.IsAccepted {
|
||||
return 0, errors.New(response.RejectReason)
|
||||
}
|
||||
return response.CancelOrderID, nil
|
||||
}
|
||||
|
||||
// CancelAllExistingOrders cancels all open orders by symbol.
|
||||
// symbol - Instrument code (ex: “BTCUSD”)
|
||||
func (e *Exchange) CancelAllExistingOrders(ctx context.Context, omsid string) error {
|
||||
req := make(map[string]any)
|
||||
req["OMSId"] = omsid
|
||||
response := Response{}
|
||||
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx,
|
||||
exchange.RestSpot,
|
||||
http.MethodPost,
|
||||
alphapointCancelAllOrders,
|
||||
req,
|
||||
&response,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !response.IsAccepted {
|
||||
return errors.New(response.RejectReason)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetOrders returns all current open orders
|
||||
func (e *Exchange) GetOrders(ctx context.Context) ([]OpenOrders, error) {
|
||||
response := OrderInfo{}
|
||||
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx,
|
||||
exchange.RestSpot,
|
||||
http.MethodPost,
|
||||
alphapointOpenOrders,
|
||||
map[string]any{},
|
||||
&response,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !response.IsAccepted {
|
||||
return nil, errors.New(response.RejectReason)
|
||||
}
|
||||
return response.OpenOrders, nil
|
||||
}
|
||||
|
||||
// GetOrderFee returns a fee associated with an order
|
||||
// symbol - Instrument code (ex: “BTCUSD”)
|
||||
// side - “buy” or “sell”
|
||||
// quantity - Quantity
|
||||
// price - Price in USD
|
||||
func (e *Exchange) GetOrderFee(ctx context.Context, symbol, side string, quantity, price float64) (float64, error) {
|
||||
req := make(map[string]any)
|
||||
req["ins"] = symbol
|
||||
req["side"] = side
|
||||
req["qty"] = strconv.FormatFloat(quantity, 'f', -1, 64)
|
||||
req["px"] = strconv.FormatFloat(price, 'f', -1, 64)
|
||||
response := Response{}
|
||||
|
||||
err := e.SendAuthenticatedHTTPRequest(ctx,
|
||||
exchange.RestSpot,
|
||||
http.MethodPost,
|
||||
alphapointOrderFee,
|
||||
req,
|
||||
&response,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if !response.IsAccepted {
|
||||
return 0, errors.New(response.RejectReason)
|
||||
}
|
||||
return response.Fee, nil
|
||||
}
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (e *Exchange) SendHTTPRequest(ctx context.Context, ep exchange.URL, method, path string, data map[string]any, result any) error {
|
||||
endpoint, err := e.API.Endpoints.GetURL(ep)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
headers := make(map[string]string)
|
||||
headers["Content-Type"] = "application/json"
|
||||
path = fmt.Sprintf("%s/ajax/v%s/%s", endpoint, alphapointAPIVersion, path)
|
||||
|
||||
PayloadJSON, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return errors.New("unable to JSON request")
|
||||
}
|
||||
|
||||
item := &request.Item{
|
||||
Method: method,
|
||||
Path: path,
|
||||
Headers: headers,
|
||||
Result: result,
|
||||
Verbose: e.Verbose,
|
||||
HTTPDebugging: e.HTTPDebugging,
|
||||
HTTPRecording: e.HTTPRecording,
|
||||
}
|
||||
|
||||
return e.SendPayload(ctx, request.Unset, func() (*request.Item, error) {
|
||||
item.Body = bytes.NewBuffer(PayloadJSON)
|
||||
return item, nil
|
||||
}, request.UnauthenticatedRequest)
|
||||
}
|
||||
|
||||
// SendAuthenticatedHTTPRequest sends an authenticated request
|
||||
func (e *Exchange) SendAuthenticatedHTTPRequest(ctx context.Context, ep exchange.URL, method, path string, data map[string]any, result any) error {
|
||||
creds, err := e.GetCredentials(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
endpoint, err := e.API.Endpoints.GetURL(ep)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n := e.Requester.GetNonce(nonce.UnixNano)
|
||||
|
||||
headers := make(map[string]string)
|
||||
headers["Content-Type"] = "application/json"
|
||||
data["apiKey"] = creds.Key
|
||||
data["apiNonce"] = n
|
||||
|
||||
hmac, err := crypto.GetHMAC(crypto.HashSHA256,
|
||||
[]byte(n.String()+creds.ClientID+creds.Key),
|
||||
[]byte(creds.Secret))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data["apiSig"] = strings.ToUpper(hex.EncodeToString(hmac))
|
||||
path = fmt.Sprintf("%s/ajax/v%s/%s", endpoint, alphapointAPIVersion, path)
|
||||
|
||||
PayloadJSON, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return errors.New("unable to JSON request")
|
||||
}
|
||||
|
||||
item := &request.Item{
|
||||
Method: method,
|
||||
Path: path,
|
||||
Headers: headers,
|
||||
Result: result,
|
||||
NonceEnabled: true,
|
||||
Verbose: e.Verbose,
|
||||
HTTPDebugging: e.HTTPDebugging,
|
||||
HTTPRecording: e.HTTPRecording,
|
||||
}
|
||||
|
||||
return e.SendPayload(ctx, request.Unset, func() (*request.Item, error) {
|
||||
item.Body = bytes.NewBuffer(PayloadJSON)
|
||||
return item, nil
|
||||
}, request.AuthenticatedRequest)
|
||||
}
|
||||
@@ -1,545 +0,0 @@
|
||||
package alphapoint
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/encoding/json"
|
||||
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/sharedtestvalues"
|
||||
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
|
||||
)
|
||||
|
||||
const (
|
||||
onlineTest = false
|
||||
apiKey = ""
|
||||
apiSecret = ""
|
||||
canManipulateRealOrders = false
|
||||
)
|
||||
|
||||
var e = &Exchange{}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
e = new(Exchange)
|
||||
e.SetDefaults()
|
||||
|
||||
if apiKey != "" && apiSecret != "" {
|
||||
e.API.AuthenticatedSupport = true
|
||||
e.SetCredentials(apiKey, apiSecret, "", "", "", "")
|
||||
}
|
||||
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
var ticker Ticker
|
||||
var err error
|
||||
if onlineTest {
|
||||
ticker, err = e.GetTicker(t.Context(), "BTCUSD")
|
||||
if err != nil {
|
||||
t.Fatal("Alphapoint GetTicker init error: ", err)
|
||||
}
|
||||
|
||||
_, err = e.GetTicker(t.Context(), "wigwham")
|
||||
if err == nil {
|
||||
t.Error("Alphapoint GetTicker Expected error")
|
||||
}
|
||||
} else {
|
||||
mockResp := []byte(
|
||||
string(`{"high":253.101,"last":249.76,"bid":248.8901,"volume":5.813354,"low":231.21,"ask":248.9012,"Total24HrQtyTraded":52.654968,"Total24HrProduct2Traded":569.05762,"Total24HrNumTrades":4,"sellOrderCount":7,"buyOrderCount":11,"numOfCreateOrders":0,"isAccepted":true}`),
|
||||
)
|
||||
|
||||
err = json.Unmarshal(mockResp, &ticker)
|
||||
if err != nil {
|
||||
t.Fatal("Alphapoint GetTicker unmarshalling error: ", err)
|
||||
}
|
||||
|
||||
if ticker.Last != 249.76 {
|
||||
t.Error("Alphapoint GetTicker expected last = 249.76")
|
||||
}
|
||||
}
|
||||
|
||||
if ticker.Last < 0 {
|
||||
t.Error("Alphapoint GetTicker last < 0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
var trades Trades
|
||||
var err error
|
||||
if onlineTest {
|
||||
trades, err = e.GetTrades(t.Context(), "BTCUSD", 0, 10)
|
||||
if err != nil {
|
||||
t.Fatalf("Init error: %s", err)
|
||||
}
|
||||
|
||||
_, err = e.GetTrades(t.Context(), "wigwham", 0, 10)
|
||||
if err == nil {
|
||||
t.Fatal("GetTrades Expected error")
|
||||
}
|
||||
} else {
|
||||
mockResp := []byte(
|
||||
string(`{"isAccepted":true,"dateTimeUtc":635507981548085938,"ins":"BTCUSD","startIndex":0,"count":10,"trades":[{"tid":0,"px":231.8379,"qty":4.913,"unixtime":1399951989,"utcticks":635355487898355234,"incomingOrderSide":0,"incomingServerOrderId":2598,"bookServerOrderId":2588},{"tid":1,"px":7895.1487,"qty":0.25,"unixtime":1403143708,"utcticks":635387405087297421,"incomingOrderSide":0,"incomingServerOrderId":284241,"bookServerOrderId":284235},{"tid":2,"px":7935.058,"qty":0.25,"unixtime":1403195348,"utcticks":635387921488684140,"incomingOrderSide":0,"incomingServerOrderId":575845,"bookServerOrderId":574078},{"tid":3,"px":7935.0448,"qty":0.25,"unixtime":1403195378,"utcticks":635387921780090390,"incomingOrderSide":0,"incomingServerOrderId":576028,"bookServerOrderId":575946},{"tid":4,"px":7933.9566,"qty":0.1168,"unixtime":1403195510,"utcticks":635387923108371640,"incomingOrderSide":0,"incomingServerOrderId":576974,"bookServerOrderId":576947},{"tid":5,"px":7961.0856,"qty":0.25,"unixtime":1403202307,"utcticks":635387991073850156,"incomingOrderSide":0,"incomingServerOrderId":600547,"bookServerOrderId":600338},{"tid":6,"px":7961.1388,"qty":0.011,"unixtime":1403202307,"utcticks":635387991073850156,"incomingOrderSide":0,"incomingServerOrderId":600547,"bookServerOrderId":600418},{"tid":7,"px":7961.2451,"qty":0.02,"unixtime":1403202307,"utcticks":635387991073850156,"incomingOrderSide":0,"incomingServerOrderId":600547,"bookServerOrderId":600428},{"tid":8,"px":7947.1437,"qty":0.09,"unixtime":1403202749,"utcticks":635387995498225156,"incomingOrderSide":0,"incomingServerOrderId":602183,"bookServerOrderId":601745},{"tid":9,"px":7818.5073,"qty":0.25,"unixtime":1403219720,"utcticks":635388165206506406,"incomingOrderSide":0,"incomingServerOrderId":661909,"bookServerOrderId":661620}]}`),
|
||||
)
|
||||
|
||||
err = json.Unmarshal(mockResp, &trades)
|
||||
if err != nil {
|
||||
t.Fatal("GetTrades unmarshalling error: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
if !trades.IsAccepted {
|
||||
t.Error("GetTrades IsAccepted failed")
|
||||
}
|
||||
|
||||
if trades.Count <= 0 {
|
||||
t.Error("GetTrades trades count is <= 0")
|
||||
}
|
||||
|
||||
if trades.Instrument != "BTCUSD" {
|
||||
t.Error("GetTrades instrument is != BTCUSD")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderbook(t *testing.T) {
|
||||
t.Parallel()
|
||||
var orderBook Orderbook
|
||||
var err error
|
||||
if onlineTest {
|
||||
orderBook, err = e.GetOrderbook(t.Context(), "BTCUSD")
|
||||
if err != nil {
|
||||
t.Errorf("Init error: %s", err)
|
||||
}
|
||||
|
||||
_, err = e.GetOrderbook(t.Context(), "wigwham")
|
||||
if err == nil {
|
||||
t.Error("GetOrderbook() Expected error")
|
||||
}
|
||||
} else {
|
||||
mockResp := []byte(
|
||||
string(`{"bids":[{"qty":725,"px":66},{"qty":1289,"px":65},{"qty":1266,"px":64}],"asks":[{"qty":1,"px":67},{"qty":1,"px":69},{"qty":2,"px":70}],"isAccepted":true}`),
|
||||
)
|
||||
|
||||
err = json.Unmarshal(mockResp, &orderBook)
|
||||
if err != nil {
|
||||
t.Fatal("TestGetOrderbook unmarshalling error: ", err)
|
||||
}
|
||||
|
||||
if orderBook.Bids[0].Quantity != 725 {
|
||||
t.Error("TestGetOrderbook Bids[0].Quantity != 725")
|
||||
}
|
||||
}
|
||||
|
||||
if !orderBook.IsAccepted {
|
||||
t.Error("Alphapoint orderBook.IsAccepted value is negative")
|
||||
}
|
||||
|
||||
if len(orderBook.Asks) == 0 {
|
||||
t.Error("Alphapoint orderBook.Asks has len 0")
|
||||
}
|
||||
|
||||
if len(orderBook.Bids) == 0 {
|
||||
t.Error("Alphapoint orderBook.Bids has len 0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetProductPairs(t *testing.T) {
|
||||
t.Parallel()
|
||||
var products ProductPairs
|
||||
var err error
|
||||
|
||||
if onlineTest {
|
||||
products, err = e.GetProductPairs(t.Context())
|
||||
if err != nil {
|
||||
t.Errorf("Init error: %s", err)
|
||||
}
|
||||
} else {
|
||||
mockResp := []byte(
|
||||
string(`{"productPairs":[{"name":"LTCUSD","productPairCode":100,"product1Label":"LTC","product1DecimalPlaces":8,"product2Label":"USD","product2DecimalPlaces":6}, {"name":"BTCUSD","productPairCode":99,"product1Label":"BTC","product1DecimalPlaces":8,"product2Label":"USD","product2DecimalPlaces":6}],"isAccepted":true}`),
|
||||
)
|
||||
|
||||
err = json.Unmarshal(mockResp, &products)
|
||||
if err != nil {
|
||||
t.Fatal("TestGetProductPairs unmarshalling error: ", err)
|
||||
}
|
||||
|
||||
if products.ProductPairs[0].Name != "LTCUSD" {
|
||||
t.Error("Alphapoint ProductPairs 0 != LTCUSD")
|
||||
}
|
||||
|
||||
if products.ProductPairs[1].Product1Label != "BTC" {
|
||||
t.Error("Alphapoint ProductPairs 1 != BTC")
|
||||
}
|
||||
}
|
||||
|
||||
if !products.IsAccepted {
|
||||
t.Error("Alphapoint ProductPairs.IsAccepted value is negative")
|
||||
}
|
||||
|
||||
if len(products.ProductPairs) == 0 {
|
||||
t.Error("Alphapoint ProductPairs len is 0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetProducts(t *testing.T) {
|
||||
t.Parallel()
|
||||
var products Products
|
||||
var err error
|
||||
|
||||
if onlineTest {
|
||||
products, err = e.GetProducts(t.Context())
|
||||
if err != nil {
|
||||
t.Errorf("Init error: %s", err)
|
||||
}
|
||||
} else {
|
||||
mockResp := []byte(
|
||||
string(`{"products": [{"name": "USD","isDigital": false,"productCode": 0,"decimalPlaces": 4,"fullName": "US Dollar"},{"name": "BTC","isDigital": true,"productCode": 1,"decimalPlaces": 6,"fullName": "Bitcoin"}],"isAccepted": true}`),
|
||||
)
|
||||
|
||||
err = json.Unmarshal(mockResp, &products)
|
||||
if err != nil {
|
||||
t.Fatal("TestGetProducts unmarshalling error: ", err)
|
||||
}
|
||||
|
||||
if products.Products[0].Name != "USD" {
|
||||
t.Error("Alphapoint Products 0 != USD")
|
||||
}
|
||||
|
||||
if products.Products[1].ProductCode != 1 {
|
||||
t.Error("Alphapoint Products 1 product code != 1")
|
||||
}
|
||||
}
|
||||
|
||||
if !products.IsAccepted {
|
||||
t.Error("Alphapoint Products.IsAccepted value is negative")
|
||||
}
|
||||
|
||||
if len(products.Products) == 0 {
|
||||
t.Error("Alphapoint Products len is 0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateAccount(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
||||
|
||||
err := e.CreateAccount(t.Context(),
|
||||
"test", "account", "something@something.com", "0292383745", "lolcat123")
|
||||
if err != nil {
|
||||
t.Errorf("Init error: %s", err)
|
||||
}
|
||||
err = e.CreateAccount(t.Context(),
|
||||
"test", "account", "something@something.com", "0292383745", "bla")
|
||||
if err == nil {
|
||||
t.Errorf("CreateAccount() Expected error")
|
||||
}
|
||||
err = e.CreateAccount(t.Context(), "", "", "", "", "lolcat123")
|
||||
if err == nil {
|
||||
t.Errorf("CreateAccount() Expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetUserInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
||||
|
||||
_, err := e.GetUserInfo(t.Context())
|
||||
if err == nil {
|
||||
t.Error("GetUserInfo() Expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetUserInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
||||
|
||||
_, err := e.SetUserInfo(t.Context(),
|
||||
"bla", "bla", "1", "meh", true, true)
|
||||
if err == nil {
|
||||
t.Error("GetUserInfo() Expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAccountInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
||||
|
||||
_, err := e.UpdateAccountInfo(t.Context(), asset.Spot)
|
||||
if err == nil {
|
||||
t.Error("GetUserInfo() Expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAccountTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
||||
|
||||
_, err := e.GetAccountTrades(t.Context(), "", 1, 2)
|
||||
if err == nil {
|
||||
t.Error("GetUserInfo() Expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDepositAddresses(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
||||
|
||||
_, err := e.GetDepositAddresses(t.Context())
|
||||
if err == nil {
|
||||
t.Error("GetUserInfo() Expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdrawCoins(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
||||
|
||||
err := e.WithdrawCoins(t.Context(), "", "", "", 0.01)
|
||||
if err == nil {
|
||||
t.Error("GetUserInfo() Expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
||||
|
||||
_, err := e.CreateOrder(t.Context(),
|
||||
"", "", order.Limit.String(), 0.01, 0)
|
||||
if err == nil {
|
||||
t.Error("GetUserInfo() Expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestModifyExistingOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
||||
|
||||
_, err := e.ModifyExistingOrder(t.Context(), "", 1, 1)
|
||||
if err == nil {
|
||||
t.Error("GetUserInfo() Expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelAllExistingOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
||||
|
||||
err := e.CancelAllExistingOrders(t.Context(), "")
|
||||
if err == nil {
|
||||
t.Error("GetUserInfo() Expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
||||
|
||||
_, err := e.GetOrders(t.Context())
|
||||
if err == nil {
|
||||
t.Error("GetUserInfo() Expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderFee(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, e)
|
||||
|
||||
_, err := e.GetOrderFee(t.Context(), "", "", 1, 1)
|
||||
if err == nil {
|
||||
t.Error("GetUserInfo() Expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatWithdrawPermissions(t *testing.T) {
|
||||
t.Parallel()
|
||||
expectedResult := exchange.AutoWithdrawCryptoWithAPIPermissionText + " & " + exchange.WithdrawCryptoWith2FAText + " & " + exchange.NoFiatWithdrawalsText
|
||||
withdrawPermissions := e.FormatWithdrawPermissions()
|
||||
if withdrawPermissions != expectedResult {
|
||||
t.Errorf("Expected: %s, Received: %s", expectedResult, withdrawPermissions)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetActiveOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
getOrdersRequest := order.MultiOrderRequest{
|
||||
Type: order.AnyType,
|
||||
AssetType: asset.Spot,
|
||||
Side: order.AnySide,
|
||||
}
|
||||
|
||||
_, err := e.GetActiveOrders(t.Context(), &getOrdersRequest)
|
||||
if sharedtestvalues.AreAPICredentialsSet(e) && err != nil {
|
||||
t.Errorf("Could not get open orders: %s", err)
|
||||
} else if !sharedtestvalues.AreAPICredentialsSet(e) && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
getOrdersRequest := order.MultiOrderRequest{
|
||||
Type: order.AnyType,
|
||||
AssetType: asset.Spot,
|
||||
Side: order.AnySide,
|
||||
}
|
||||
|
||||
_, err := e.GetOrderHistory(t.Context(), &getOrdersRequest)
|
||||
if sharedtestvalues.AreAPICredentialsSet(e) && err != nil {
|
||||
t.Errorf("Could not get order history: %s", err)
|
||||
} else if !sharedtestvalues.AreAPICredentialsSet(e) && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
}
|
||||
|
||||
// Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them
|
||||
// ----------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
func TestSubmitOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, e, canManipulateRealOrders)
|
||||
|
||||
orderSubmission := &order.Submit{
|
||||
Exchange: e.Name,
|
||||
Pair: currency.Pair{
|
||||
Delimiter: "_",
|
||||
Base: currency.BTC,
|
||||
Quote: currency.USD,
|
||||
},
|
||||
Side: order.Buy,
|
||||
Type: order.Limit,
|
||||
Price: 1,
|
||||
Amount: 1,
|
||||
ClientID: "meowOrder",
|
||||
AssetType: asset.Spot,
|
||||
}
|
||||
|
||||
response, err := e.SubmitOrder(t.Context(), orderSubmission)
|
||||
if !sharedtestvalues.AreAPICredentialsSet(e) && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if sharedtestvalues.AreAPICredentialsSet(e) && err != nil {
|
||||
t.Errorf("Withdraw failed to be placed: %v", err)
|
||||
|
||||
if response.Status != order.New {
|
||||
t.Errorf("Order failed to be placed: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelExchangeOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, e, canManipulateRealOrders)
|
||||
|
||||
currencyPair := currency.NewPair(currency.BTC, currency.LTC)
|
||||
orderCancellation := &order.Cancel{
|
||||
OrderID: "1",
|
||||
AccountID: "1",
|
||||
Pair: currencyPair,
|
||||
AssetType: asset.Spot,
|
||||
}
|
||||
|
||||
err := e.CancelOrder(t.Context(), orderCancellation)
|
||||
if !sharedtestvalues.AreAPICredentialsSet(e) && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if sharedtestvalues.AreAPICredentialsSet(e) && err != nil {
|
||||
t.Errorf("Withdraw failed to be placed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, e, canManipulateRealOrders)
|
||||
|
||||
currencyPair := currency.NewPair(currency.BTC, currency.LTC)
|
||||
orderCancellation := &order.Cancel{
|
||||
OrderID: "1",
|
||||
AccountID: "1",
|
||||
Pair: currencyPair,
|
||||
AssetType: asset.Spot,
|
||||
}
|
||||
|
||||
resp, err := e.CancelAllOrders(t.Context(), orderCancellation)
|
||||
if !sharedtestvalues.AreAPICredentialsSet(e) && err == nil {
|
||||
t.Error("Expecting an error when no keys are set")
|
||||
}
|
||||
if sharedtestvalues.AreAPICredentialsSet(e) && err != nil {
|
||||
t.Errorf("Withdraw failed to be placed: %v", err)
|
||||
}
|
||||
|
||||
if len(resp.Status) > 0 {
|
||||
t.Errorf("%v orders failed to cancel", len(resp.Status))
|
||||
}
|
||||
}
|
||||
|
||||
func TestModifyOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
||||
_, err := e.ModifyOrder(t.Context(), &order.Modify{AssetType: asset.Spot})
|
||||
if err == nil {
|
||||
t.Error("ModifyOrder() Expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdraw(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := e.WithdrawCryptocurrencyFunds(t.Context(),
|
||||
&withdraw.Request{})
|
||||
if err != common.ErrNotYetImplemented {
|
||||
t.Errorf("Expected 'Not implemented', received %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdrawFiat(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
||||
|
||||
_, err := e.WithdrawFiatFunds(t.Context(),
|
||||
&withdraw.Request{})
|
||||
if err != common.ErrNotYetImplemented {
|
||||
t.Errorf("Expected '%v', received: '%v'", common.ErrNotYetImplemented, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdrawInternationalBank(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, e, canManipulateRealOrders)
|
||||
|
||||
_, err := e.WithdrawFiatFundsToInternationalBank(t.Context(), &withdraw.Request{})
|
||||
if err != common.ErrNotYetImplemented {
|
||||
t.Errorf("Expected '%v', received: '%v'", common.ErrNotYetImplemented, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRecentTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
currencyPair, err := currency.NewPairFromString("btc_usdt")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = e.GetRecentTrades(t.Context(), currencyPair, asset.Spot)
|
||||
if err != nil && err != common.ErrNotYetImplemented {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetHistoricTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
currencyPair, err := currency.NewPairFromString("btc_usdt")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = e.GetHistoricTrades(t.Context(),
|
||||
currencyPair, asset.Spot, time.Now().Add(-time.Minute*15), time.Now())
|
||||
if err != nil && err != common.ErrNotYetImplemented {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -1,215 +0,0 @@
|
||||
package alphapoint
|
||||
|
||||
import (
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/types"
|
||||
)
|
||||
|
||||
// Response contains general responses from the exchange
|
||||
type Response struct {
|
||||
IsAccepted bool `json:"isAccepted"`
|
||||
RejectReason string `json:"rejectReason"`
|
||||
Fee float64 `json:"fee"`
|
||||
FeeProduct string `json:"feeProduct"`
|
||||
CancelOrderID int64 `json:"cancelOrderId"`
|
||||
ServerOrderID int64 `json:"serverOrderId"`
|
||||
DateTimeUTC types.Time `json:"dateTimeUtc"`
|
||||
ModifyOrderID int64 `json:"modifyOrderId"`
|
||||
Addresses []DepositAddresses
|
||||
}
|
||||
|
||||
// Ticker holds ticker information
|
||||
type Ticker struct {
|
||||
High float64 `json:"high"`
|
||||
Last float64 `json:"last"`
|
||||
Bid float64 `json:"bid"`
|
||||
Volume float64 `json:"volume"`
|
||||
Low float64 `json:"low"`
|
||||
Ask float64 `json:"ask"`
|
||||
Total24HrQtyTraded float64 `json:"Total24HrQtyTraded"`
|
||||
Total24HrNumTrades float64 `json:"Total24HrNumTrades"`
|
||||
SellOrderCount float64 `json:"sellOrderCount"`
|
||||
BuyOrderCount float64 `json:"buyOrderCount"`
|
||||
NumOfCreateOrders float64 `json:"numOfCreateOrders"`
|
||||
IsAccepted bool `json:"isAccepted"`
|
||||
RejectReason string `json:"rejectReason"`
|
||||
}
|
||||
|
||||
// Trades holds trade information
|
||||
type Trades struct {
|
||||
IsAccepted bool `json:"isAccepted"`
|
||||
RejectReason string `json:"rejectReason"`
|
||||
DateTimeUTC types.Time `json:"dateTimeUtc"`
|
||||
Instrument string `json:"ins"`
|
||||
StartIndex int `json:"startIndex"`
|
||||
Count int `json:"count"`
|
||||
StartDate int64 `json:"startDate"`
|
||||
EndDate int64 `json:"endDate"`
|
||||
Trades []Trade `json:"trades"`
|
||||
}
|
||||
|
||||
// Trade is a sub-type which holds the singular trade that occurred in the past
|
||||
type Trade struct {
|
||||
TID int64 `json:"tid"`
|
||||
Price float64 `json:"px"`
|
||||
Quantity float64 `json:"qty"`
|
||||
Unixtime int `json:"unixtime"`
|
||||
UTCTicks int64 `json:"utcticks"`
|
||||
IncomingOrderSide int `json:"incomingOrderSide"`
|
||||
IncomingServerOrderID int `json:"incomingServerOrderId"`
|
||||
BookServerOrderID int `json:"bookServerOrderId"`
|
||||
}
|
||||
|
||||
// Orderbook holds the total Bids and Asks on the exchange
|
||||
type Orderbook struct {
|
||||
Bids []OrderbookEntry `json:"bids"`
|
||||
Asks []OrderbookEntry `json:"asks"`
|
||||
IsAccepted bool `json:"isAccepted"`
|
||||
RejectReason string `json:"rejectReason"`
|
||||
}
|
||||
|
||||
// OrderbookEntry is a sub-type that takes has the individual quantity and price
|
||||
type OrderbookEntry struct {
|
||||
Quantity float64 `json:"qty"`
|
||||
Price float64 `json:"px"`
|
||||
}
|
||||
|
||||
// ProductPairs holds the full range of product pairs that the exchange can
|
||||
// trade between
|
||||
type ProductPairs struct {
|
||||
ProductPairs []ProductPair `json:"productPairs"`
|
||||
IsAccepted bool `json:"isAccepted"`
|
||||
RejectReason string `json:"rejectReason"`
|
||||
}
|
||||
|
||||
// ProductPair holds the individual product pairs that are currently traded
|
||||
type ProductPair struct {
|
||||
Name string `json:"name"`
|
||||
Productpaircode int `json:"productPairCode"`
|
||||
Product1Label string `json:"product1Label"`
|
||||
Product1Decimalplaces int `json:"product1DecimalPlaces"`
|
||||
Product2Label string `json:"product2Label"`
|
||||
Product2Decimalplaces int `json:"product2DecimalPlaces"`
|
||||
}
|
||||
|
||||
// Products holds the full range of supported currency products
|
||||
type Products struct {
|
||||
Products []Product `json:"products"`
|
||||
IsAccepted bool `json:"isAccepted"`
|
||||
RejectReason string `json:"rejectReason"`
|
||||
}
|
||||
|
||||
// Product holds the a single currency product that is supported
|
||||
type Product struct {
|
||||
Name string `json:"name"`
|
||||
IsDigital bool `json:"isDigital"`
|
||||
ProductCode int `json:"productCode"`
|
||||
DecimalPlaces int `json:"decimalPlaces"`
|
||||
FullName string `json:"fullName"`
|
||||
}
|
||||
|
||||
// UserInfo holds current user information associated with the apiKey details
|
||||
type UserInfo struct {
|
||||
UserInforKVPs []UserInfoKVP `json:"userInfoKVP"`
|
||||
IsAccepted bool `json:"isAccepted"`
|
||||
RejectReason string `json:"rejectReason"`
|
||||
}
|
||||
|
||||
// UserInfoKVP is a sub-type that holds key value pairs
|
||||
type UserInfoKVP struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// UserInfoSet is the returned response from set user information request
|
||||
type UserInfoSet struct {
|
||||
IsAccepted string `json:"isAccepted"`
|
||||
RejectReason string `json:"rejectReason"`
|
||||
RequireAuthy2FA bool `json:"requireAuthy2FA"`
|
||||
Val2FaRequestCode string `json:"val2FaRequestCode"`
|
||||
}
|
||||
|
||||
// AccountInfo holds your current account information like balances, trade count
|
||||
// and volume
|
||||
type AccountInfo struct {
|
||||
Currencies []struct {
|
||||
Name string `json:"name"`
|
||||
Balance int `json:"balance"`
|
||||
Hold int `json:"hold"`
|
||||
} `json:"currencies"`
|
||||
ProductPairs []struct {
|
||||
ProductPairName string `json:"productPairName"`
|
||||
ProductPairCode int `json:"productPairCode"`
|
||||
TradeCount int `json:"tradeCount"`
|
||||
TradeVolume int `json:"tradeVolume"`
|
||||
} `json:"productPairs"`
|
||||
IsAccepted bool `json:"isAccepted"`
|
||||
RejectReason string `json:"rejectReason"`
|
||||
}
|
||||
|
||||
// Order is a generalised order type
|
||||
type Order struct {
|
||||
ServerOrderID int `json:"ServerOrderId"`
|
||||
AccountID int `json:"AccountId"`
|
||||
Price float64 `json:"Price"`
|
||||
QtyTotal float64 `json:"QtyTotal"`
|
||||
QtyRemaining float64 `json:"QtyRemaining"`
|
||||
ReceiveTime types.Time `json:"ReceiveTime"`
|
||||
Side int64 `json:"Side"`
|
||||
State int `json:"orderState"`
|
||||
OrderType int `json:"orderType"`
|
||||
}
|
||||
|
||||
// OpenOrders holds the full range of orders by instrument
|
||||
type OpenOrders struct {
|
||||
Instrument string `json:"ins"`
|
||||
OpenOrders []Order `json:"openOrders"`
|
||||
}
|
||||
|
||||
// OrderInfo holds all open orders across the entire range of all instruments
|
||||
type OrderInfo struct {
|
||||
OpenOrders []OpenOrders `json:"openOrdersInfo"`
|
||||
IsAccepted bool `json:"isAccepted"`
|
||||
DateTimeUTC types.Time `json:"dateTimeUtc"`
|
||||
RejectReason string `json:"rejectReason"`
|
||||
}
|
||||
|
||||
// DepositAddresses holds information about the generated deposit address for
|
||||
// a specific currency
|
||||
type DepositAddresses struct {
|
||||
Name string `json:"name"`
|
||||
DepositAddress string `json:"depositAddress"`
|
||||
}
|
||||
|
||||
// WebsocketTicker holds current up to date ticker information
|
||||
type WebsocketTicker struct {
|
||||
MessageType string `json:"messageType"`
|
||||
ProductPair string `json:"prodPair"`
|
||||
High float64 `json:"high"`
|
||||
Low float64 `json:"low"`
|
||||
Last float64 `json:"last"`
|
||||
Volume float64 `json:"volume"`
|
||||
Volume24Hrs float64 `json:"volume24hrs"`
|
||||
Volume24HrsProduct2 float64 `json:"volume24hrsProduct2"`
|
||||
Total24HrQtyTraded float64 `json:"Total24HrQtyTraded"`
|
||||
Total24HrProduct2Traded float64 `json:"Total24HrProduct2Traded"`
|
||||
Total24HrNumTrades float64 `json:"Total24HrNumTrades"`
|
||||
Bid float64 `json:"bid"`
|
||||
Ask float64 `json:"ask"`
|
||||
BuyOrderCount int `json:"buyOrderCount"`
|
||||
SellOrderCount int `json:"sellOrderCount"`
|
||||
}
|
||||
|
||||
// orderSideMap holds order type info based on Alphapoint data
|
||||
var orderSideMap = map[int64]order.Side{
|
||||
1: order.Buy,
|
||||
2: order.Sell,
|
||||
}
|
||||
|
||||
// orderTypeMap holds order type info based on Alphapoint data
|
||||
var orderTypeMap = map[int]order.Type{
|
||||
1: order.Market,
|
||||
2: order.Limit,
|
||||
3: order.Stop,
|
||||
6: order.TrailingStop,
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
package alphapoint
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
gws "github.com/gorilla/websocket"
|
||||
"github.com/thrasher-corp/gocryptotrader/encoding/json"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/log"
|
||||
)
|
||||
|
||||
const (
|
||||
alphapointDefaultWebsocketURL = "wss://sim3.alphapoint.com:8401/v1/GetTicker/"
|
||||
)
|
||||
|
||||
// WebsocketClient starts a new webstocket connection
|
||||
func (e *Exchange) WebsocketClient() {
|
||||
for e.Enabled {
|
||||
var dialer gws.Dialer
|
||||
var err error
|
||||
var httpResp *http.Response
|
||||
endpoint, err := e.API.Endpoints.GetURL(exchange.WebsocketSpot)
|
||||
if err != nil {
|
||||
log.Errorln(log.WebsocketMgr, err)
|
||||
}
|
||||
e.WebsocketConn, httpResp, err = dialer.Dial(endpoint, http.Header{})
|
||||
httpResp.Body.Close() // not used, so safely free the body
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(log.ExchangeSys, "%s Unable to connect to Websocket. Error: %s\n", e.Name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if e.Verbose {
|
||||
log.Debugf(log.ExchangeSys, "%s Connected to Websocket.\n", e.Name)
|
||||
}
|
||||
|
||||
err = e.WebsocketConn.WriteMessage(gws.TextMessage, []byte(`{"messageType": "logon"}`))
|
||||
if err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
return
|
||||
}
|
||||
|
||||
for e.Enabled {
|
||||
msgType, resp, err := e.WebsocketConn.ReadMessage()
|
||||
if err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
break
|
||||
}
|
||||
|
||||
if msgType == gws.TextMessage {
|
||||
type MsgType struct {
|
||||
MessageType string `json:"messageType"`
|
||||
}
|
||||
|
||||
msgType := MsgType{}
|
||||
err := json.Unmarshal(resp, &msgType)
|
||||
if err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if msgType.MessageType == "Ticker" {
|
||||
ticker := WebsocketTicker{}
|
||||
err = json.Unmarshal(resp, &ticker)
|
||||
if err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
e.WebsocketConn.Close()
|
||||
log.Debugf(log.ExchangeSys, "%s Websocket client disconnected.", e.Name)
|
||||
}
|
||||
}
|
||||
@@ -1,446 +0,0 @@
|
||||
package alphapoint
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/deposit"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/fundingrate"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/futures"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/protocol"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/trade"
|
||||
"github.com/thrasher-corp/gocryptotrader/log"
|
||||
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
|
||||
)
|
||||
|
||||
// SetDefaults sets current default settings
|
||||
func (e *Exchange) SetDefaults() {
|
||||
e.Name = "Alphapoint"
|
||||
e.Enabled = true
|
||||
e.Verbose = true
|
||||
e.API.Endpoints = e.NewEndpoints()
|
||||
err := e.API.Endpoints.SetDefaultEndpoints(map[exchange.URL]string{
|
||||
exchange.RestSpot: alphapointDefaultAPIURL,
|
||||
exchange.WebsocketSpot: alphapointDefaultWebsocketURL,
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
}
|
||||
e.API.CredentialsValidator.RequiresKey = true
|
||||
e.API.CredentialsValidator.RequiresSecret = true
|
||||
|
||||
e.Features = exchange.Features{
|
||||
Supports: exchange.FeaturesSupported{
|
||||
REST: true,
|
||||
Websocket: true,
|
||||
RESTCapabilities: protocol.Features{
|
||||
AccountInfo: true,
|
||||
TickerFetching: true,
|
||||
TradeFetching: true,
|
||||
OrderbookFetching: true,
|
||||
GetOrders: true,
|
||||
CancelOrder: true,
|
||||
CancelOrders: true,
|
||||
SubmitOrder: true,
|
||||
ModifyOrder: true,
|
||||
UserTradeHistory: true,
|
||||
CryptoDeposit: true,
|
||||
CryptoWithdrawal: true,
|
||||
TradeFee: true,
|
||||
},
|
||||
|
||||
WebsocketCapabilities: protocol.Features{
|
||||
AccountInfo: true,
|
||||
},
|
||||
|
||||
WithdrawPermissions: exchange.WithdrawCryptoWith2FA |
|
||||
exchange.AutoWithdrawCryptoWithAPIPermission |
|
||||
exchange.NoFiatWithdrawals,
|
||||
},
|
||||
}
|
||||
|
||||
e.Requester, err = request.New(e.Name,
|
||||
common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout))
|
||||
if err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Setup takes in the supplied exchange configuration details and sets params
|
||||
func (e *Exchange) Setup(_ *config.Exchange) error {
|
||||
return common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// FetchTradablePairs returns a list of the exchanges tradable pairs
|
||||
func (e *Exchange) FetchTradablePairs(_ context.Context, _ asset.Item) (currency.Pairs, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetServerTime returns the current exchange server time.
|
||||
func (e *Exchange) GetServerTime(_ context.Context, _ asset.Item) (time.Time, error) {
|
||||
return time.Time{}, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// UpdateTradablePairs updates the exchanges available pairs and stores
|
||||
// them in the exchanges config
|
||||
func (e *Exchange) UpdateTradablePairs(_ context.Context, _ bool) error {
|
||||
return common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// UpdateAccountInfo retrieves balances for all enabled currencies on the
|
||||
// Alphapoint exchange
|
||||
func (e *Exchange) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (account.Holdings, error) {
|
||||
var response account.Holdings
|
||||
response.Exchange = e.Name
|
||||
acc, err := e.GetAccountInformation(ctx)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
balances := make([]account.Balance, len(acc.Currencies))
|
||||
for i := range acc.Currencies {
|
||||
balances[i] = account.Balance{
|
||||
Currency: currency.NewCode(acc.Currencies[i].Name),
|
||||
Total: float64(acc.Currencies[i].Balance),
|
||||
Hold: float64(acc.Currencies[i].Hold),
|
||||
Free: float64(acc.Currencies[i].Balance) - float64(acc.Currencies[i].Hold),
|
||||
}
|
||||
}
|
||||
|
||||
response.Accounts = append(response.Accounts, account.SubAccount{
|
||||
Currencies: balances,
|
||||
AssetType: assetType,
|
||||
})
|
||||
|
||||
creds, err := e.GetCredentials(ctx)
|
||||
if err != nil {
|
||||
return account.Holdings{}, err
|
||||
}
|
||||
|
||||
err = account.Process(&response, creds)
|
||||
if err != nil {
|
||||
return account.Holdings{}, err
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// UpdateTickers updates the ticker for all currency pairs of a given asset type
|
||||
func (e *Exchange) UpdateTickers(_ context.Context, _ asset.Item) error {
|
||||
return common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// UpdateTicker updates and returns the ticker for a currency pair
|
||||
func (e *Exchange) UpdateTicker(ctx context.Context, p currency.Pair, assetType asset.Item) (*ticker.Price, error) {
|
||||
if p.IsEmpty() {
|
||||
return nil, currency.ErrCurrencyPairEmpty
|
||||
}
|
||||
if err := e.CurrencyPairs.IsAssetEnabled(assetType); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tick, err := e.GetTicker(ctx, p.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = ticker.ProcessTicker(&ticker.Price{
|
||||
Pair: p,
|
||||
Ask: tick.Ask,
|
||||
Bid: tick.Bid,
|
||||
Low: tick.Low,
|
||||
High: tick.High,
|
||||
Volume: tick.Volume,
|
||||
Last: tick.Last,
|
||||
ExchangeName: e.Name,
|
||||
AssetType: assetType,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ticker.GetTicker(e.Name, p, assetType)
|
||||
}
|
||||
|
||||
// UpdateOrderbook updates and returns the orderbook for a currency pair
|
||||
func (e *Exchange) UpdateOrderbook(ctx context.Context, p currency.Pair, assetType asset.Item) (*orderbook.Book, error) {
|
||||
if p.IsEmpty() {
|
||||
return nil, currency.ErrCurrencyPairEmpty
|
||||
}
|
||||
if err := e.CurrencyPairs.IsAssetEnabled(assetType); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orderBook := new(orderbook.Book)
|
||||
orderbookNew, err := e.GetOrderbook(ctx, p.String())
|
||||
if err != nil {
|
||||
return orderBook, err
|
||||
}
|
||||
|
||||
orderBook.Bids = make(orderbook.Levels, len(orderbookNew.Bids))
|
||||
for x := range orderbookNew.Bids {
|
||||
orderBook.Bids[x] = orderbook.Level{
|
||||
Amount: orderbookNew.Bids[x].Quantity,
|
||||
Price: orderbookNew.Bids[x].Price,
|
||||
}
|
||||
}
|
||||
|
||||
orderBook.Asks = make(orderbook.Levels, len(orderbookNew.Asks))
|
||||
for x := range orderbookNew.Asks {
|
||||
orderBook.Asks[x] = orderbook.Level{
|
||||
Amount: orderbookNew.Asks[x].Quantity,
|
||||
Price: orderbookNew.Asks[x].Price,
|
||||
}
|
||||
}
|
||||
|
||||
orderBook.Pair = p
|
||||
orderBook.Exchange = e.Name
|
||||
orderBook.Asset = assetType
|
||||
|
||||
err = orderBook.Process()
|
||||
if err != nil {
|
||||
return orderBook, err
|
||||
}
|
||||
|
||||
return orderbook.Get(e.Name, p, assetType)
|
||||
}
|
||||
|
||||
// GetAccountFundingHistory returns funding history, deposits and
|
||||
// withdrawals
|
||||
func (e *Exchange) GetAccountFundingHistory(_ context.Context) ([]exchange.FundingHistory, error) {
|
||||
// https://alphapoint.github.io/slate/#generatetreasuryactivityreport
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetWithdrawalsHistory returns previous withdrawals data
|
||||
func (e *Exchange) GetWithdrawalsHistory(_ context.Context, _ currency.Code, _ asset.Item) ([]exchange.WithdrawalHistory, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetRecentTrades returns the most recent trades for a currency and asset
|
||||
func (e *Exchange) GetRecentTrades(_ context.Context, _ currency.Pair, _ asset.Item) ([]trade.Data, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetHistoricTrades returns historic trade data within the timeframe provided
|
||||
func (e *Exchange) GetHistoricTrades(_ context.Context, _ currency.Pair, _ asset.Item, _, _ time.Time) ([]trade.Data, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// SubmitOrder submits a new order and returns a true value when
|
||||
// successfully submitted
|
||||
func (e *Exchange) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := s.Validate(e.GetTradingRequirements()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fPair, err := e.FormatExchangeCurrency(s.Pair, s.AssetType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response, err := e.CreateOrder(ctx,
|
||||
fPair.String(),
|
||||
s.Side.String(),
|
||||
s.Type.String(),
|
||||
s.Amount,
|
||||
s.Price)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.DeriveSubmitResponse(strconv.FormatInt(response, 10))
|
||||
}
|
||||
|
||||
// ModifyOrder will allow of changing orderbook placement and limit to
|
||||
// market conversion
|
||||
func (e *Exchange) ModifyOrder(_ context.Context, _ *order.Modify) (*order.ModifyResponse, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// CancelOrder cancels an order by its corresponding ID number
|
||||
func (e *Exchange) CancelOrder(ctx context.Context, o *order.Cancel) error {
|
||||
if err := o.Validate(o.StandardCancel()); err != nil {
|
||||
return err
|
||||
}
|
||||
orderIDInt, err := strconv.ParseInt(o.OrderID, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = e.CancelExistingOrder(ctx, orderIDInt, o.AccountID)
|
||||
return err
|
||||
}
|
||||
|
||||
// CancelBatchOrders cancels an orders by their corresponding ID numbers
|
||||
func (e *Exchange) CancelBatchOrders(_ context.Context, _ []order.Cancel) (*order.CancelBatchResponse, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// CancelAllOrders cancels all orders for a given account
|
||||
func (e *Exchange) CancelAllOrders(ctx context.Context, orderCancellation *order.Cancel) (order.CancelAllResponse, error) {
|
||||
if err := orderCancellation.Validate(); err != nil {
|
||||
return order.CancelAllResponse{}, err
|
||||
}
|
||||
return order.CancelAllResponse{},
|
||||
e.CancelAllExistingOrders(ctx, orderCancellation.AccountID)
|
||||
}
|
||||
|
||||
// GetOrderInfo returns order information based on order ID
|
||||
func (e *Exchange) GetOrderInfo(_ context.Context, _ string, _ currency.Pair, _ asset.Item) (*order.Detail, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetDepositAddress returns a deposit address for a specified currency
|
||||
func (e *Exchange) GetDepositAddress(ctx context.Context, cryptocurrency currency.Code, _, _ string) (*deposit.Address, error) {
|
||||
addresses, err := e.GetDepositAddresses(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for x := range addresses {
|
||||
if addresses[x].Name == cryptocurrency.String() {
|
||||
return &deposit.Address{
|
||||
Address: addresses[x].DepositAddress,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("associated currency address not found")
|
||||
}
|
||||
|
||||
// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is
|
||||
// submitted
|
||||
func (e *Exchange) WithdrawCryptocurrencyFunds(_ context.Context, _ *withdraw.Request) (*withdraw.ExchangeResponse, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// WithdrawFiatFunds returns a withdrawal ID when a withdrawal is submitted
|
||||
func (e *Exchange) WithdrawFiatFunds(_ context.Context, _ *withdraw.Request) (*withdraw.ExchangeResponse, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a withdrawal is
|
||||
// submitted
|
||||
func (e *Exchange) WithdrawFiatFundsToInternationalBank(_ context.Context, _ *withdraw.Request) (*withdraw.ExchangeResponse, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetFeeByType returns an estimate of fee based on type of transaction
|
||||
func (e *Exchange) GetFeeByType(_ context.Context, _ *exchange.FeeBuilder) (float64, error) {
|
||||
return 0, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetActiveOrders retrieves any orders that are active/open
|
||||
// This function is not concurrency safe due to orderSide/orderType maps
|
||||
func (e *Exchange) GetActiveOrders(ctx context.Context, req *order.MultiOrderRequest) (order.FilteredOrders, error) {
|
||||
err := req.Validate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := e.GetOrders(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var orders []order.Detail
|
||||
for x := range resp {
|
||||
for y := range resp[x].OpenOrders {
|
||||
if resp[x].OpenOrders[y].State != 1 {
|
||||
continue
|
||||
}
|
||||
orders = append(orders, order.Detail{
|
||||
Amount: resp[x].OpenOrders[y].QtyTotal,
|
||||
Exchange: e.Name,
|
||||
ExecutedAmount: resp[x].OpenOrders[y].QtyTotal - resp[x].OpenOrders[y].QtyRemaining,
|
||||
AccountID: strconv.FormatInt(int64(resp[x].OpenOrders[y].AccountID), 10),
|
||||
OrderID: strconv.FormatInt(int64(resp[x].OpenOrders[y].ServerOrderID), 10),
|
||||
Price: resp[x].OpenOrders[y].Price,
|
||||
RemainingAmount: resp[x].OpenOrders[y].QtyRemaining,
|
||||
Side: orderSideMap[resp[x].OpenOrders[y].Side],
|
||||
Date: resp[x].OpenOrders[y].ReceiveTime.Time(),
|
||||
Type: orderTypeMap[resp[x].OpenOrders[y].OrderType],
|
||||
})
|
||||
}
|
||||
}
|
||||
return req.Filter(e.Name, orders), nil
|
||||
}
|
||||
|
||||
// GetOrderHistory retrieves account order information
|
||||
// Can Limit response to specific order status
|
||||
// This function is not concurrency safe due to orderSide/orderType maps
|
||||
func (e *Exchange) GetOrderHistory(ctx context.Context, req *order.MultiOrderRequest) (order.FilteredOrders, error) {
|
||||
err := req.Validate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := e.GetOrders(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var orders []order.Detail
|
||||
for x := range resp {
|
||||
for y := range resp[x].OpenOrders {
|
||||
if resp[x].OpenOrders[y].State == 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
orders = append(orders, order.Detail{
|
||||
Amount: resp[x].OpenOrders[y].QtyTotal,
|
||||
AccountID: strconv.FormatInt(int64(resp[x].OpenOrders[y].AccountID), 10),
|
||||
Exchange: e.Name,
|
||||
ExecutedAmount: resp[x].OpenOrders[y].QtyTotal - resp[x].OpenOrders[y].QtyRemaining,
|
||||
OrderID: strconv.FormatInt(int64(resp[x].OpenOrders[y].ServerOrderID), 10),
|
||||
Price: resp[x].OpenOrders[y].Price,
|
||||
RemainingAmount: resp[x].OpenOrders[y].QtyRemaining,
|
||||
Side: orderSideMap[resp[x].OpenOrders[y].Side],
|
||||
Date: resp[x].OpenOrders[y].ReceiveTime.Time(),
|
||||
Type: orderTypeMap[resp[x].OpenOrders[y].OrderType],
|
||||
})
|
||||
}
|
||||
}
|
||||
return req.Filter(e.Name, orders), nil
|
||||
}
|
||||
|
||||
// ValidateAPICredentials validates current credentials used for wrapper
|
||||
// functionality
|
||||
func (e *Exchange) ValidateAPICredentials(ctx context.Context, assetType asset.Item) error {
|
||||
_, err := e.UpdateAccountInfo(ctx, assetType)
|
||||
return e.CheckTransientError(err)
|
||||
}
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func (e *Exchange) GetHistoricCandles(_ context.Context, _ currency.Pair, _ asset.Item, _ kline.Interval, _, _ time.Time) (*kline.Item, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetHistoricCandlesExtended returns candles between a time period for a set
|
||||
// time interval
|
||||
func (e *Exchange) GetHistoricCandlesExtended(_ context.Context, _ currency.Pair, _ asset.Item, _ kline.Interval, _, _ time.Time) (*kline.Item, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetFuturesContractDetails returns all contracts from the exchange by asset type
|
||||
func (e *Exchange) GetFuturesContractDetails(context.Context, asset.Item) ([]futures.Contract, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetLatestFundingRates returns the latest funding rates data
|
||||
func (e *Exchange) GetLatestFundingRates(context.Context, *fundingrate.LatestRateRequest) ([]fundingrate.LatestRateResponse, error) {
|
||||
return nil, common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// UpdateOrderExecutionLimits updates order execution limits
|
||||
func (e *Exchange) UpdateOrderExecutionLimits(_ context.Context, _ asset.Item) error {
|
||||
return common.ErrNotYetImplemented
|
||||
}
|
||||
@@ -40,7 +40,7 @@ func TestLessByPrice(t *testing.T) {
|
||||
}
|
||||
localItems := []Item{
|
||||
{
|
||||
Exchange: "alphapoint",
|
||||
Exchange: "bitstamp",
|
||||
Pair: p,
|
||||
AssetType: asset.Spot,
|
||||
Price: 1200,
|
||||
|
||||
@@ -59,7 +59,6 @@ _b in this context is an `IBotExchange` implemented struct_
|
||||
|
||||
| Exchange | Recent Trades via REST | Live trade updates via Websocket | Trade history via REST |
|
||||
|----------|------|-----------|-----|
|
||||
| Alphapoint | No | No | No |
|
||||
| Binance.US | Yes | Yes | NA |
|
||||
| Binance| Yes | Yes | Yes |
|
||||
| Bitfinex | Yes | Yes | Yes |
|
||||
|
||||
Reference in New Issue
Block a user