Skip to content

Commit

Permalink
Poloniex: Implementation of GetOrderInfo method (thrasher-corp#607)
Browse files Browse the repository at this point in the history
* GetClosedOrder implemented for Kraken and Binance, fixed Binance MARKET order creaton, added rate, fee and cost fileds on SubmitOrder responce

* return Trades on Binance SubmitOrder, new validation methods on Binance and kraken GetClosedOrderInfo

* removed the Binance extra method GetClosedOrder

* func description corrected

* removed price, fee and cost from SimulateOrder response, as we get all necessary info in response to calculate them on client side

* GetClosedOrder implementation moved to GetOrderInfo

* changed GetOrderInfo params

* removed Canceled order.Type used for Kraken

* update QueryOrder in gctscript

* add missed params to QueryOrder validator (gctscript)

* fixed testing issues

* GetClosedOrder implemented for Kraken and Binance, fixed Binance MARKET order creaton, added rate, fee and cost fileds on SubmitOrder responce

* return Trades on Binance SubmitOrder, new validation methods on Binance and kraken GetClosedOrderInfo

* removed the Binance extra method GetClosedOrder

* func description corrected

* removed price, fee and cost from SimulateOrder response, as we get all necessary info in response to calculate them on client side

* GetClosedOrder implementation moved to GetOrderInfo

* changed GetOrderInfo params

* removed Canceled order.Type used for Kraken

* update QueryOrder in gctscript

* add missed params to QueryOrder validator (gctscript)

* fixed testing issues

* pull previous changes

* linter issues fix

* updated query_order exmple in gctscript, fixed params check

* removed orderPair unnecessary conversion

* added wsCancelAllOrders, fixed bugs

* fixed Kraken wsAddOrder method

* cleanup

* CancelBatchOrders implementation

* changed CancelBatchOrders signature

* fixed tests and wrappers

* btcmarkets_test fix

* cleanup

* cleanup

* changed CancelBatchOrders signature

* fmt

* Update configtest.json

* Update configtest.json

* rollback configtest

* refactored Kraken wsHandleData to allow tests

* removed unnecessary error test in TestWsAddOrderJSON

* dependencies updates

* fixed issue with PortfolioSleepDelay set on startup

* add GetWithdrawalsHistory method to exchanges interface

* param name changes

* add extra params for Binance WithdrawStatus method

* add Binance TestWithdrawHistory

* add GetOrderInfo on Poloniex

* linter errors fix

* switch interface type to avoid panic

* Poloniex has no para errror in OrderbookResponse - removed, added seq param (incrementing sequence) for future use

* linter issues fix

* linter issues fix

* dependencies update

* add tests

* refactored unmarshalling of GetAuthenticatedOrderStatus response

* test fix

* linter issues fix

* unmarshaling logic moved to GetAuthenticatedOrderStatus

* forced Status setting on GetAuthenticatedOrderStatus error

* comment edited

Co-authored-by: Vazha Bezhanishvili <[email protected]>
  • Loading branch information
vazha and Vazha Bezhanishvili authored Dec 14, 2020
1 parent ddd19ab commit 622e5dc
Show file tree
Hide file tree
Showing 11 changed files with 1,789 additions and 1,376 deletions.
14 changes: 12 additions & 2 deletions engine/rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -851,8 +851,18 @@ func (s *RPCServer) GetOrder(_ context.Context, r *gctrpc.GetOrderRequest) (*gct
AssetType: result.Trades[i].Type.String(),
OrderSide: result.Trades[i].Side.String(),
Fee: result.Trades[i].Fee,
Total: result.Trades[i].Total,
})
}

var creationTime, updateTime int64
if result.Date.Unix() > 0 {
creationTime = result.Date.Unix()
}
if result.CloseTime.Unix() > 0 {
updateTime = result.CloseTime.Unix()
}

return &gctrpc.OrderDetails{
Exchange: result.Exchange,
Id: result.ID,
Expand All @@ -861,15 +871,15 @@ func (s *RPCServer) GetOrder(_ context.Context, r *gctrpc.GetOrderRequest) (*gct
AssetType: result.AssetType.String(),
OrderSide: result.Side.String(),
OrderType: result.Type.String(),
CreationTime: result.Date.Unix(),
CreationTime: creationTime,
Status: result.Status.String(),
Price: result.Price,
Amount: result.Amount,
OpenVolume: result.RemainingAmount,
Fee: result.Fee,
Trades: trades,
Cost: result.Cost,
UpdateTime: result.CloseTime.Unix(),
UpdateTime: updateTime,
}, err
}

Expand Down
1 change: 1 addition & 0 deletions exchanges/order/order_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ type TradeHistory struct {
Timestamp time.Time
IsMaker bool
FeeAsset string
Total float64
}

// GetOrdersRequest used for GetOrderHistory and GetOpenOrders wrapper functions
Expand Down
78 changes: 78 additions & 0 deletions exchanges/poloniex/poloniex.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ const (
poloniexDepositsWithdrawals = "returnDepositsWithdrawals"
poloniexOrders = "returnOpenOrders"
poloniexTradeHistory = "returnTradeHistory"
poloniexOrderTrades = "returnOrderTrades"
poloniexOrderStatus = "returnOrderStatus"
poloniexOrderCancel = "cancelOrder"
poloniexOrderMove = "moveOrder"
poloniexWithdraw = "withdraw"
Expand Down Expand Up @@ -418,6 +420,82 @@ func (p *Poloniex) GetAuthenticatedTradeHistory(start, end, limit int64) (Authen
return mainResult, json.Unmarshal(result, &mainResult.Data)
}

// GetAuthenticatedOrderStatus returns the status of a given orderId.
func (p *Poloniex) GetAuthenticatedOrderStatus(orderID string) (o OrderStatusData, err error) {
values := url.Values{}

if orderID == "" {
return o, fmt.Errorf("no orderID passed")
}

values.Set("orderNumber", orderID)
var rawOrderStatus OrderStatus
err = p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexOrderStatus, values, &rawOrderStatus)
if err != nil {
return o, err
}

switch rawOrderStatus.Success {
case 0: // fail
var errMsg GenericResponse
err = json.Unmarshal(rawOrderStatus.Result, &errMsg)
if err != nil {
return o, err
}
return o, fmt.Errorf(errMsg.Error)
case 1: // success
var status map[string]OrderStatusData
err = json.Unmarshal(rawOrderStatus.Result, &status)
if err != nil {
return o, err
}

for _, o = range status {
return o, err
}
}

return o, err
}

// GetAuthenticatedOrderTrades returns all trades involving a given orderId.
func (p *Poloniex) GetAuthenticatedOrderTrades(orderID string) (o []OrderTrade, err error) {
values := url.Values{}

if orderID == "" {
return nil, fmt.Errorf("no orderId passed")
}

values.Set("orderNumber", orderID)
var result json.RawMessage
err = p.SendAuthenticatedHTTPRequest(http.MethodPost, poloniexOrderTrades, values, &result)
if err != nil {
return nil, err
}

if len(result) == 0 {
return nil, fmt.Errorf("received unexpected response")
}

switch result[0] {
case '{': // error message received
var resp GenericResponse
err = json.Unmarshal(result, &resp)
if err != nil {
return nil, err
}
if resp.Error != "" {
err = fmt.Errorf(resp.Error)
}
case '[': // data received
err = json.Unmarshal(result, &o)
default:
return nil, fmt.Errorf("received unexpected response")
}

return o, err
}

// PlaceOrder places a new order on the exchange
func (p *Poloniex) PlaceOrder(currency string, rate, amount float64, immediate, fillOrKill, buy bool) (OrderResponse, error) {
result := OrderResponse{}
Expand Down
104 changes: 104 additions & 0 deletions exchanges/poloniex/poloniex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package poloniex

import (
"net/http"
"strings"
"testing"
"time"

Expand Down Expand Up @@ -248,6 +249,109 @@ func TestGetOrderHistory(t *testing.T) {
}
}

func TestGetOrderStatus(t *testing.T) {
t.Parallel()

tests := []struct {
name string
mock bool
orderID string
errExpected bool
errMsgExpected string
}{
{
name: "correct order ID",
mock: true,
orderID: "96238912841",
errExpected: false,
errMsgExpected: "",
},
{
name: "wrong order ID",
mock: true,
orderID: "96238912842",
errExpected: true,
errMsgExpected: "Order not found",
},
}

for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
if tt.mock != mockTests {
t.Skip()
}

_, err := p.GetAuthenticatedOrderStatus(tt.orderID)

switch {
case areTestAPIKeysSet() && err != nil:
t.Errorf("Could not get order status: %s", err)
case !areTestAPIKeysSet() && err == nil && !mockTests:
t.Error("Expecting an error when no keys are set")
case mockTests && err != nil:
if !tt.errExpected {
t.Errorf("Could not mock get order status: %s", err.Error())
} else if !(strings.Contains(err.Error(), tt.errMsgExpected)) {
t.Errorf("Could not mock get order status: %s", err.Error())
}
case mockTests:
if tt.errExpected {
t.Errorf("Mock get order status expect an error '%s', get no error", tt.errMsgExpected)
}
}
})
}
}

func TestGetOrderTrades(t *testing.T) {
t.Parallel()

tests := []struct {
name string
mock bool
orderID string
errExpected bool
errMsgExpected string
}{
{
name: "correct order ID",
mock: true,
orderID: "96238912841",
errExpected: false,
errMsgExpected: "",
},
{
name: "wrong order ID",
mock: true,
orderID: "96238912842",
errExpected: true,
errMsgExpected: "Order not found",
},
}

for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
if tt.mock != mockTests {
t.Skip()
}

_, err := p.GetAuthenticatedOrderTrades(tt.orderID)
switch {
case areTestAPIKeysSet() && err != nil:
t.Errorf("Could not get order trades: %s", err)
case !areTestAPIKeysSet() && err == nil && !mockTests:
t.Error("Expecting an error when no keys are set")
case mockTests && err != nil:
if !(tt.errExpected && strings.Contains(err.Error(), tt.errMsgExpected)) {
t.Errorf("Could not mock get order trades: %s", err)
}
}
})
}
}

// Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them
// ----------------------------------------------------------------------------------------------------------------------------

Expand Down
35 changes: 35 additions & 0 deletions exchanges/poloniex/poloniex_types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package poloniex

import (
"encoding/json"
"time"

"github.com/thrasher-corp/gocryptotrader/currency"
Expand Down Expand Up @@ -36,6 +37,7 @@ type OrderbookResponse struct {
Bids [][]interface{} `json:"bids"`
IsFrozen string `json:"isFrozen"`
Error string `json:"error"`
Seq int64 `json:"seq"`
}

// OrderbookItem holds data on an individual item
Expand Down Expand Up @@ -66,6 +68,39 @@ type TradeHistory struct {
Total float64 `json:"total,string"`
}

// OrderStatus holds order status data
type OrderStatus struct {
Result json.RawMessage `json:"result"`
Success int64 `json:"success"`
}

// OrderStatusData defines order status details
type OrderStatusData struct {
Pair string `json:"currencyPair"`
Rate float64 `json:"rate,string"`
Amount float64 `json:"amount,string"`
Total float64 `json:"total,string"`
StartingAmount float64 `json:"startingAmount,string"`
Type string `json:"type"`
Status string `json:"status"`
Date string `json:"date"`
Fee float64 `json:"fee,string"`
}

// OrderTrade holds order trade data
type OrderTrade struct {
Status string `json:"status"`
GlobalTradeID int64 `json:"globalTradeID"`
TradeID int64 `json:"tradeID"`
CurrencyPair string `json:"currencyPair"`
Type string `json:"type"`
Rate float64 `json:"rate,string"`
Amount float64 `json:"amount,string"`
Total float64 `json:"total,string"`
Fee float64 `json:"fee,string"`
Date string `json:"date"`
}

// ChartData holds kline data
type ChartData struct {
Date int64 `json:"date"`
Expand Down
60 changes: 58 additions & 2 deletions exchanges/poloniex/poloniex_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -589,8 +589,64 @@ func (p *Poloniex) CancelAllOrders(_ *order.Cancel) (order.CancelAllResponse, er

// GetOrderInfo returns order information based on order ID
func (p *Poloniex) GetOrderInfo(orderID string, pair currency.Pair, assetType asset.Item) (order.Detail, error) {
var orderDetail order.Detail
return orderDetail, common.ErrNotYetImplemented
orderInfo := order.Detail{
Exchange: p.Name,
Pair: pair,
}

trades, err := p.GetAuthenticatedOrderTrades(orderID)
if err != nil && !strings.Contains(err.Error(), "Order not found") {
return orderInfo, err
}

for i := range trades {
var tradeHistory order.TradeHistory
tradeHistory.Exchange = p.Name
tradeHistory.Side, err = order.StringToOrderSide(trades[i].Type)
if err != nil {
return orderInfo, err
}
tradeHistory.TID = strconv.FormatInt(trades[i].GlobalTradeID, 10)
tradeHistory.Timestamp, err = time.Parse(common.SimpleTimeFormat, trades[i].Date)
if err != nil {
return orderInfo, err
}
tradeHistory.Price = trades[i].Rate
tradeHistory.Amount = trades[i].Amount
tradeHistory.Total = trades[i].Total
tradeHistory.Fee = trades[i].Fee
orderInfo.Trades = append(orderInfo.Trades, tradeHistory)
}

resp, err := p.GetAuthenticatedOrderStatus(orderID)
if err != nil {
if len(orderInfo.Trades) > 0 { // on closed orders return trades only
if strings.Contains(err.Error(), "Order not found") {
orderInfo.Status = order.Closed
}
return orderInfo, nil
}
return orderInfo, err
}

orderInfo.Status, _ = order.StringToOrderStatus(resp.Status)
orderInfo.Price = resp.Rate
orderInfo.Amount = resp.Amount
orderInfo.Cost = resp.Total
orderInfo.Fee = resp.Fee
orderInfo.TargetAmount = resp.StartingAmount

orderInfo.Side, err = order.StringToOrderSide(resp.Type)
if err != nil {
return orderInfo, err
}

orderInfo.Date, err = time.Parse(common.SimpleTimeFormat, resp.Date)
if err != nil {
return orderInfo, err
}

return orderInfo, nil
}

// GetDepositAddress returns a deposit address for a specified currency
Expand Down
Loading

0 comments on commit 622e5dc

Please sign in to comment.