Skip to content

Commit

Permalink
Added Trade ws support
Browse files Browse the repository at this point in the history
  • Loading branch information
amir-the-h committed Sep 27, 2021
1 parent 855b114 commit 8847a2e
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 64 deletions.
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,15 +139,14 @@ Supporting APIs
* [Private Channel](https://www.okex.com/docs-v5/en/#websocket-api-private-channel) (except demo special trading
endpoints)
* [Public Channel](https://www.okex.com/docs-v5/en/#websocket-api-public-channels)

[comment]: <> ( * [Trade]&#40;https://www.okex.com/docs-v5/en/#websocket-api-trade&#41;)

* [Trade](https://www.okex.com/docs-v5/en/#websocket-api-trade)

Features
--------

* All [requests](/requests), [responses](/responses), and [events](events) are well types and will convert into the
system types instead of using API's strings. *Note that zero values will be replaced with non-existing data.*
* All [requests](/requests), [responses](/responses), and [events](events) are well typed and will convert into the
language built-in types instead of using API's strings. *Note that zero values will be replaced with non-existing
data.*
* Fully automated authorization steps for both [REST](/api/rest) and [WS](/api/ws)
* To receive websocket events you can choose [RawEventChan](/api/ws/client.go#L25)
, [StructuredEventChan](/api/ws/client.go#L28), or provide your own
Expand Down
109 changes: 53 additions & 56 deletions api/ws/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type ClientWs struct {
StructuredEventChan chan interface{}
Private *Private
Public *Public
Trade *Trade
SubscribeChan chan *events.Subscribe
UnsubscribeCh chan *events.Unsubscribe
sendChan map[bool]chan []byte
Expand Down Expand Up @@ -182,62 +183,6 @@ func (c *ClientWs) Send(p bool, op okex.Operation, args []map[string]string) err
return nil
}

// process the incoming event
func (c *ClientWs) process(data []byte, e *events.Basic) bool {
switch e.Event {
case "error":
e := events.Error{}
_ = json.Unmarshal(data, &e)
go func() {
c.ErrChan <- &e
}()
return true
case "subscribe":
e := events.Subscribe{}
_ = json.Unmarshal(data, &e)
go func() {
if c.SubscribeChan != nil {
c.SubscribeChan <- &e
}
c.StructuredEventChan <- e
}()
return true
case "unsubscribe":
e := events.Unsubscribe{}
_ = json.Unmarshal(data, &e)
go func() {
if c.UnsubscribeCh != nil {
c.UnsubscribeCh <- &e
}
c.StructuredEventChan <- e
}()
return true
case "login":
au := time.Now().Add(time.Second * 30)
c.AuthorizedUntil = &au
e := events.Login{}
_ = json.Unmarshal(data, &e)
go func() {
if c.LoginChan != nil {
c.LoginChan <- &e
}
c.StructuredEventChan <- e
}()
return true
default:
if c.Private.Process(data, e) {
return true
}
if c.Public.Process(data, e) {
return true
}
}

go func() { c.RawEventChan <- e }()

return false
}

// SetChannels to receive certain events on separate channel
func (c *ClientWs) SetChannels(errCh chan *events.Error, subCh chan *events.Subscribe, unSub chan *events.Unsubscribe, lCh chan *events.Login) {
c.ErrChan = errCh
Expand Down Expand Up @@ -372,3 +317,55 @@ func (c *ClientWs) handleCancel(msg string) error {
}()
return fmt.Errorf("operation cancelled: %s", msg)
}
func (c *ClientWs) process(data []byte, e *events.Basic) bool {
switch e.Event {
case "error":
e := events.Error{}
_ = json.Unmarshal(data, &e)
go func() {
c.ErrChan <- &e
}()
return true
case "subscribe":
e := events.Subscribe{}
_ = json.Unmarshal(data, &e)
go func() {
if c.SubscribeChan != nil {
c.SubscribeChan <- &e
}
c.StructuredEventChan <- e
}()
return true
case "unsubscribe":
e := events.Unsubscribe{}
_ = json.Unmarshal(data, &e)
go func() {
if c.UnsubscribeCh != nil {
c.UnsubscribeCh <- &e
}
c.StructuredEventChan <- e
}()
return true
case "login":
au := time.Now().Add(time.Second * 30)
c.AuthorizedUntil = &au
e := events.Login{}
_ = json.Unmarshal(data, &e)
go func() {
if c.LoginChan != nil {
c.LoginChan <- &e
}
c.StructuredEventChan <- e
}()
return true
}
if c.Private.Process(data, e) {
return true
}
if c.Public.Process(data, e) {
return true
}
go func() { c.RawEventChan <- e }()

return false
}
110 changes: 110 additions & 0 deletions api/ws/trade.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package ws

import (
"github.com/amir-the-h/okex"
requests "github.com/amir-the-h/okex/requests/rest/trade"
"time"
)

// Trade
//
// https://www.okex.com/docs-v5/en/#websocket-api-trade
type Trade struct {
*ClientWs
}

// NewTrade returns a pointer to a fresh Trade
func NewTrade(c *ClientWs) *Trade {
return &Trade{ClientWs: c}
}

// PlaceOrder
// You can place an order only if you have sufficient funds.
//
// https://www.okex.com/docs-v5/en/#websocket-api-trade-place-order
//
// Place orders in a batch. Maximum 20 orders can be placed at a time
//
// https://www.okex.com/docs-v5/en/#websocket-api-trade-place-multiple-orders
func (c *Trade) PlaceOrder(req ...requests.PlaceOrder) error {
tmpArgs := make([]map[string]string, len(req))
op := okex.OrderOperation
if len(req) > 1 {
op = okex.BatchOrderOperation
}
for i, order := range req {
tmpArgs[i] = okex.S2M(order)
}

if err := c.Login(); err != nil {
return err
}
c.waitForAuthorization()

return c.Send(true, op, tmpArgs)
}

// CancelOrder
// Cancel an incomplete order
//
// https://www.okex.com/docs-v5/en/#websocket-api-trade-place-order
//
// Cancel incomplete orders in batches. Maximum 20 orders can be canceled at a time.
//
// https://www.okex.com/docs-v5/en/#websocket-api-trade-cancel-multiple-orders
func (c *Trade) CancelOrder(req ...requests.CancelOrder) error {
tmpArgs := make([]map[string]string, len(req))
op := okex.CancelOrderOperation
if len(req) > 1 {
op = okex.BatchCancelOrderOperation
}
for i, order := range req {
tmpArgs[i] = okex.S2M(order)
}

if err := c.Login(); err != nil {
return err
}
c.waitForAuthorization()

return c.Send(true, op, tmpArgs)
}

// AmendOrder
// Amend an incomplete order.
//
// https://www.okex.com/docs-v5/en/#websocket-api-trade-place-order
//
// Amend incomplete orders in batches. Maximum 20 orders can be amended at a time.
//
// https://www.okex.com/docs-v5/en/#websocket-api-trade-amend-multiple-orders
func (c *Trade) AmendOrder(req ...requests.AmendOrder) error {
tmpArgs := make([]map[string]string, len(req))
op := okex.AmendOrderOperation
if len(req) > 1 {
op = okex.BatchAmendOrderOperation
}
for i, order := range req {
tmpArgs[i] = okex.S2M(order)
}

if err := c.Login(); err != nil {
return err
}
c.waitForAuthorization()

return c.Send(true, op, tmpArgs)
}

func (c *Trade) waitForAuthorization() {
if c.AuthorizedUntil != nil && time.Since(*c.AuthorizedUntil) < PingPeriod {
return
}
ticker := time.NewTicker(time.Millisecond * 300)
defer ticker.Stop()
for range ticker.C {
if c.AuthorizedUntil != nil && time.Since(*c.AuthorizedUntil) < PingPeriod {
return
}
}
}
12 changes: 9 additions & 3 deletions definitions.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,15 @@ const (
TradeBuySide = TradeSide("buy")
TradeSellSide = TradeSide("sell")

LoginOperation = Operation("login")
SubscribeOperation = Operation("subscribe")
UnsubscribeOperation = Operation("unsubscribe")
LoginOperation = Operation("login")
SubscribeOperation = Operation("subscribe")
UnsubscribeOperation = Operation("unsubscribe")
OrderOperation = Operation("order")
BatchOrderOperation = Operation("batch-orders")
CancelOrderOperation = Operation("cancel-order")
BatchCancelOrderOperation = Operation("batch-cancel-orders")
AmendOrderOperation = Operation("amend-order")
BatchAmendOrderOperation = Operation("batch-amend-orders")

OrderMarket = OrderType("market")
OrderLimit = OrderType("limit")
Expand Down

0 comments on commit 8847a2e

Please sign in to comment.