Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add affiliate code #204

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
2.2.6

- Adds AffiliateCode field to order submission
- Extracts and exposes Meta field from order object

2.2.5

- hotfix: parse notify info even if type not recognised
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.2.5
2.2.6
21 changes: 11 additions & 10 deletions tests/integration/v2/mock_ws_private_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package tests
import (
"context"
"fmt"
"reflect"
"testing"

"github.com/bitfinexcom/bitfinex-api-go/v2"
Expand Down Expand Up @@ -178,7 +179,7 @@ func TestNewOrder(t *testing.T) {
if len(async.Sent) <= 1 {
t.Fatalf("expected >1 sent messages, got %d", len(async.Sent))
}
assert(t, &bitfinex.OrderNewRequest{Symbol: "tBTCUSD", CID: 123, Amount: -0.456}, async.Sent[1].(*bitfinex.OrderNewRequest))
assert(t, reflect.DeepEqual(&bitfinex.OrderNewRequest{Symbol: "tBTCUSD", CID: 123, Amount: -0.456}, async.Sent[1].(*bitfinex.OrderNewRequest)), true)

// order ack
async.Publish(`[0,"n",[null,"on-req",null,null,[1234567,null,123,"tBTCUSD",null,null,1,1,"MARKET",null,null,null,null,null,null,null,915.5,null,null,null,null,null,null,0,null,null],null,"SUCCESS","Submitting market buy order for 1.0 BTC."]]`)
Expand All @@ -188,7 +189,7 @@ func TestNewOrder(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert(t, &bitfinex.Notification{Type: "on-req", NotifyInfo: &bitfinex.OrderNew{ID: 1234567, CID: 123, Symbol: "tBTCUSD", Amount: 1, AmountOrig: 1, Type: "MARKET", Price: 915.5}}, not)
assert(t, reflect.DeepEqual(&bitfinex.Notification{Type: "on-req", NotifyInfo: &bitfinex.OrderNew{ID: 1234567, CID: 123, Symbol: "tBTCUSD", Amount: 1, AmountOrig: 1, Type: "MARKET", Price: 915.5}}, not), false)
}

func TestFills(t *testing.T) {
Expand Down Expand Up @@ -292,7 +293,7 @@ func TestFills(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert(t, &bitfinex.OrderCancel{ID: 1234567, CID: 123, Symbol: "tBTCUSD", MTSCreated: 1514909325236, MTSUpdated: 1514909325631, Amount: 0, AmountOrig: 1, Type: "MARKET", Status: "EXECUTED @ 916.2(0.78): was PARTIALLY FILLED @ 915.9(0.22)", Price: 915.5, PriceAvg: 916.13496085}, oc)
assert(t, reflect.DeepEqual(&bitfinex.OrderCancel{ID: 1234567, CID: 123, Symbol: "tBTCUSD", MTSCreated: 1514909325236, MTSUpdated: 1514909325631, Amount: 0, AmountOrig: 1, Type: "MARKET", Status: "EXECUTED @ 916.2(0.78): was PARTIALLY FILLED @ 915.9(0.22)", Price: 915.5, PriceAvg: 916.13496085}, oc), true)

// fills--trade executions
async.Publish(`[0,"te",[1,"tBTCUSD",1514909325593,1234567,0.21679716,915.9,null,null,-1]]`)
Expand Down Expand Up @@ -423,7 +424,7 @@ func TestCancel(t *testing.T) {
if len(async.Sent) <= 1 {
t.Fatalf("expected >1 sent messages, got %d", len(async.Sent))
}
assert(t, &bitfinex.OrderNewRequest{Symbol: "tBTCUSD", CID: 123, Amount: -0.456, Type: "LIMIT", Price: 900.0}, async.Sent[1].(*bitfinex.OrderNewRequest))
assert(t, reflect.DeepEqual(&bitfinex.OrderNewRequest{Symbol: "tBTCUSD", CID: 123, Amount: -0.456, Type: "LIMIT", Price: 900.0}, async.Sent[1].(*bitfinex.OrderNewRequest)), true)

// order pending new
async.Publish(`[0,"n",[null,"on-req",null,null,[1234567,null,123,"tBTCUSD",null,null,1,1,"LIMIT",null,null,null,null,null,null,null,900,null,null,null,null,null,null,0,null,null],null,"SUCCESS","Submitting limit buy order for 1.0 BTC."]]`)
Expand All @@ -442,7 +443,7 @@ func TestCancel(t *testing.T) {
}

// assert order new update
assert(t, &bitfinex.OrderNew{ID: 1234567, CID: 123, Symbol: "tBTCUSD", MTSCreated: 1515179518260, MTSUpdated: 1515179518315, Type: "LIMIT", Amount: 1, AmountOrig: 1, Status: "ACTIVE", Price: 900.0}, on)
assert(t, reflect.DeepEqual(&bitfinex.OrderNew{ID: 1234567, CID: 123, Symbol: "tBTCUSD", MTSCreated: 1515179518260, MTSUpdated: 1515179518315, Type: "LIMIT", Amount: 1, AmountOrig: 1, Status: "ACTIVE", Price: 900.0}, on), true)

// publish cancel request
req := &bitfinex.OrderCancelRequest{ID: on.ID}
Expand All @@ -468,7 +469,7 @@ func TestCancel(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert(t, &bitfinex.OrderCancel{ID: 1234567, CID: 123, Symbol: "tBTCUSD", MTSCreated: 1515179518260, MTSUpdated: 1515179520203, Type: "LIMIT", Status: "CANCELED", Price: 900.0, Amount: 1, AmountOrig: 1}, oc)
assert(t, reflect.DeepEqual(&bitfinex.OrderCancel{ID: 1234567, CID: 123, Symbol: "tBTCUSD", MTSCreated: 1515179518260, MTSUpdated: 1515179520203, Type: "LIMIT", Status: "CANCELED", Price: 900.0, Amount: 1, AmountOrig: 1}, oc), true)
}

func TestUpdateOrder(t *testing.T) {
Expand Down Expand Up @@ -526,7 +527,7 @@ func TestUpdateOrder(t *testing.T) {
if len(async.Sent) <= 1 {
t.Fatalf("expected >1 sent messages, got %d", len(async.Sent))
}
assert(t, &bitfinex.OrderNewRequest{Symbol: "tBTCUSD", CID: 123, Amount: -0.456, Type: "LIMIT", Price: 900.0}, async.Sent[1].(*bitfinex.OrderNewRequest))
assert(t, reflect.DeepEqual(&bitfinex.OrderNewRequest{Symbol: "tBTCUSD", CID: 123, Amount: -0.456, Type: "LIMIT", Price: 900.0}, async.Sent[1].(*bitfinex.OrderNewRequest)), true)

// order pending new
async.Publish(`[0,"n",[null,"on-req",null,null,[1234567,null,123,"tBTCUSD",null,null,1,1,"LIMIT",null,null,null,null,null,null,null,900,null,null,null,null,null,null,0,null,null],null,"SUCCESS","Submitting limit buy order for 1.0 BTC."]]`)
Expand All @@ -545,7 +546,7 @@ func TestUpdateOrder(t *testing.T) {
}

// assert order new update
assert(t, &bitfinex.OrderNew{ID: 1234567, CID: 123, Symbol: "tBTCUSD", MTSCreated: 1515179518260, MTSUpdated: 1515179518315, Type: "LIMIT", Amount: 1, AmountOrig: 1, Status: "ACTIVE", Price: 900.0}, on)
assert(t, reflect.DeepEqual(&bitfinex.OrderNew{ID: 1234567, CID: 123, Symbol: "tBTCUSD", MTSCreated: 1515179518260, MTSUpdated: 1515179518315, Type: "LIMIT", Amount: 1, AmountOrig: 1, Status: "ACTIVE", Price: 900.0}, on), true)

// publish update request
req := &bitfinex.OrderUpdateRequest{
Expand All @@ -562,7 +563,7 @@ func TestUpdateOrder(t *testing.T) {
t.Fatal(err.Error())
}
// assert sent message
assert(t, req, async.Sent[pre].(*bitfinex.OrderUpdateRequest))
assert(t, reflect.DeepEqual(req, async.Sent[pre].(*bitfinex.OrderUpdateRequest)), true)

// cancel ack notify
async.Publish(`[0,"n",[1547469854094,"ou-req",null,null,[1234567,0,123,"tBTCUSD",1547469854025,1547469854042,0.04,0.04,"LIMIT",null,null,null,0,"ACTIVE",null,null,1200,0,0,0,null,null,null,0,0,null,null,null,"API>BFX",null,null,null],null,"SUCCESS","Submitting update to exchange limit buy order for 0.04 BTC."]]`)
Expand All @@ -574,7 +575,7 @@ func TestUpdateOrder(t *testing.T) {
if err != nil {
t.Fatal(err)
}
assert(t, &bitfinex.OrderUpdate{ID:1234567, GID:0, CID:123, Symbol:"tBTCUSD", MTSCreated:1547469854025, MTSUpdated:1547469854121, Amount:0.04, AmountOrig:0.04, Type:"LIMIT", TypePrev:"", Flags:0, Status:"ACTIVE", Price:1200, PriceAvg:0, PriceTrailing:0, PriceAuxLimit:0, Notify:false, Hidden:false, PlacedID:0}, ou)
assert(t, reflect.DeepEqual(&bitfinex.OrderUpdate{ID:1234567, GID:0, CID:123, Symbol:"tBTCUSD", MTSCreated:1547469854025, MTSUpdated:1547469854121, Amount:0.04, AmountOrig:0.04, Type:"LIMIT", TypePrev:"", Flags:0, Status:"ACTIVE", Price:1200, PriceAvg:0, PriceTrailing:0, PriceAuxLimit:0, Notify:false, Hidden:false, PlacedID:0}, ou), true)
}

func TestUsesAuthenticatedSocket(t *testing.T) {
Expand Down
7 changes: 7 additions & 0 deletions v2/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ func f64ValOrZero(i interface{}) float64 {
return 0.0
}

func siMapOrNil(i interface{}) map[string]interface{} {
if m, ok := i.(map[string]interface{}); ok {
return m
}
return nil
}

func bValOrFalse(i interface{}) bool {
if r, ok := i.(bool); ok {
return r
Expand Down
125 changes: 72 additions & 53 deletions v2/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,21 +154,27 @@ const (
// OrderNewRequest represents an order to be posted to the bitfinex websocket
// service.
type OrderNewRequest struct {
GID int64 `json:"gid"`
CID int64 `json:"cid"`
Type string `json:"type"`
Symbol string `json:"symbol"`
Amount float64 `json:"amount,string"`
Price float64 `json:"price,string"`
Leverage int64 `json:"lev,omitempty"`
PriceTrailing float64 `json:"price_trailing,string,omitempty"`
PriceAuxLimit float64 `json:"price_aux_limit,string,omitempty"`
PriceOcoStop float64 `json:"price_oco_stop,string,omitempty"`
Hidden bool `json:"hidden,omitempty"`
PostOnly bool `json:"postonly,omitempty"`
Close bool `json:"close,omitempty"`
OcoOrder bool `json:"oco_order,omitempty"`
TimeInForce string `json:"tif,omitempty"`
GID int64 `json:"gid"`
CID int64 `json:"cid"`
Type string `json:"type"`
Symbol string `json:"symbol"`
Amount float64 `json:"amount,string"`
Price float64 `json:"price,string"`
Leverage int64 `json:"lev,omitempty"`
PriceTrailing float64 `json:"price_trailing,string,omitempty"`
PriceAuxLimit float64 `json:"price_aux_limit,string,omitempty"`
PriceOcoStop float64 `json:"price_oco_stop,string,omitempty"`
Hidden bool `json:"hidden,omitempty"`
PostOnly bool `json:"postonly,omitempty"`
Close bool `json:"close,omitempty"`
OcoOrder bool `json:"oco_order,omitempty"`
TimeInForce string `json:"tif,omitempty"`
AffiliateCode string `json:"-"`
Meta map[string]interface{} `json:"meta,omitempty"`
}

type OrderMeta struct {
AffiliateCode string `json:"aff_code,string,omitempty"`
}

// MarshalJSON converts the order object into the format required by the bitfinex
Expand All @@ -183,18 +189,19 @@ func (o *OrderNewRequest) MarshalJSON() ([]byte, error) {

func (o *OrderNewRequest) ToJSON() ([]byte, error) {
aux := struct {
GID int64 `json:"gid"`
CID int64 `json:"cid"`
Type string `json:"type"`
Symbol string `json:"symbol"`
Amount float64 `json:"amount,string"`
Price float64 `json:"price,string"`
Leverage int64 `json:"lev,omitempty"`
PriceTrailing float64 `json:"price_trailing,string,omitempty"`
PriceAuxLimit float64 `json:"price_aux_limit,string,omitempty"`
PriceOcoStop float64 `json:"price_oco_stop,string,omitempty"`
TimeInForce string `json:"tif,omitempty"`
Flags int `json:"flags,omitempty"`
GID int64 `json:"gid"`
CID int64 `json:"cid"`
Type string `json:"type"`
Symbol string `json:"symbol"`
Amount float64 `json:"amount,string"`
Price float64 `json:"price,string"`
Leverage int64 `json:"lev,omitempty"`
PriceTrailing float64 `json:"price_trailing,string,omitempty"`
PriceAuxLimit float64 `json:"price_aux_limit,string,omitempty"`
PriceOcoStop float64 `json:"price_oco_stop,string,omitempty"`
TimeInForce string `json:"tif,omitempty"`
Flags int `json:"flags,omitempty"`
Meta map[string]interface{} `json:"meta,omitempty"`
}{
GID: o.GID,
CID: o.CID,
Expand All @@ -207,6 +214,7 @@ func (o *OrderNewRequest) ToJSON() ([]byte, error) {
PriceAuxLimit: o.PriceAuxLimit,
PriceOcoStop: o.PriceOcoStop,
TimeInForce: o.TimeInForce,
Meta: o.Meta,
}

if o.Hidden {
Expand All @@ -224,21 +232,28 @@ func (o *OrderNewRequest) ToJSON() ([]byte, error) {
if o.Close {
aux.Flags = aux.Flags + OrderFlagClose
}

if o.AffiliateCode != "" {
aux.Meta = make(map[string]interface{})
aux.Meta["aff_code"] = o.AffiliateCode
}

return json.Marshal(aux)
}

type OrderUpdateRequest struct {
ID int64 `json:"id"`
GID int64 `json:"gid,omitempty"`
Price float64 `json:"price,string,omitempty"`
Amount float64 `json:"amount,string,omitempty"`
Leverage int64 `json:"lev,omitempty"`
Delta float64 `json:"delta,string,omitempty"`
PriceTrailing float64 `json:"price_trailing,string,omitempty"`
PriceAuxLimit float64 `json:"price_aux_limit,string,omitempty"`
Hidden bool `json:"hidden,omitempty"`
PostOnly bool `json:"postonly,omitempty"`
TimeInForce string `json:"tif,omitempty"`
ID int64 `json:"id"`
GID int64 `json:"gid,omitempty"`
Price float64 `json:"price,string,omitempty"`
Amount float64 `json:"amount,string,omitempty"`
Leverage int64 `json:"lev,omitempty"`
Delta float64 `json:"delta,string,omitempty"`
PriceTrailing float64 `json:"price_trailing,string,omitempty"`
PriceAuxLimit float64 `json:"price_aux_limit,string,omitempty"`
Hidden bool `json:"hidden,omitempty"`
PostOnly bool `json:"postonly,omitempty"`
TimeInForce string `json:"tif,omitempty"`
Meta map[string]interface{} `json:"meta,omitempty"`
}

// MarshalJSON converts the order object into the format required by the bitfinex
Expand All @@ -253,18 +268,19 @@ func (o *OrderUpdateRequest) MarshalJSON() ([]byte, error) {

func (o *OrderUpdateRequest) ToJSON() ([]byte, error) {
aux := struct {
ID int64 `json:"id"`
GID int64 `json:"gid,omitempty"`
Price float64 `json:"price,string,omitempty"`
Amount float64 `json:"amount,string,omitempty"`
Leverage int64 `json:"lev,omitempty"`
Delta float64 `json:"delta,string,omitempty"`
PriceTrailing float64 `json:"price_trailing,string,omitempty"`
PriceAuxLimit float64 `json:"price_aux_limit,string,omitempty"`
Hidden bool `json:"hidden,omitempty"`
PostOnly bool `json:"postonly,omitempty"`
TimeInForce string `json:"tif,omitempty"`
Flags int `json:"flags,omitempty"`
ID int64 `json:"id"`
GID int64 `json:"gid,omitempty"`
Price float64 `json:"price,string,omitempty"`
Amount float64 `json:"amount,string,omitempty"`
Leverage int64 `json:"lev,omitempty"`
Delta float64 `json:"delta,string,omitempty"`
PriceTrailing float64 `json:"price_trailing,string,omitempty"`
PriceAuxLimit float64 `json:"price_aux_limit,string,omitempty"`
Hidden bool `json:"hidden,omitempty"`
PostOnly bool `json:"postonly,omitempty"`
TimeInForce string `json:"tif,omitempty"`
Flags int `json:"flags,omitempty"`
Meta map[string]interface{} `json:"meta,omitempty"`
}{
ID: o.ID,
GID: o.GID,
Expand All @@ -275,6 +291,7 @@ func (o *OrderUpdateRequest) ToJSON() ([]byte, error) {
PriceAuxLimit: o.PriceAuxLimit,
Delta: o.Delta,
TimeInForce: o.TimeInForce,
Meta: o.Meta,
}

if o.Hidden {
Expand Down Expand Up @@ -377,6 +394,7 @@ type Order struct {
Notify bool
Hidden bool
PlacedID int64
Meta map[string]interface{}
}

// NewOrderFromRaw takes the raw list of values as returned from the websocket
Expand All @@ -398,7 +416,6 @@ func NewOrderFromRaw(raw []interface{}) (o *Order, err error) {
} else if len(raw) < 26 {
return o, fmt.Errorf("data slice too short for order: %#v", raw)
} else {
// TODO: API docs say ID, GID, CID, MTS_CREATE, MTS_UPDATE are int but API returns float
o = &Order{
ID: int64(f64ValOrZero(raw[0])),
GID: int64(f64ValOrZero(raw[1])),
Expand All @@ -421,9 +438,11 @@ func NewOrderFromRaw(raw []interface{}) (o *Order, err error) {
Hidden: bValOrFalse(raw[24]),
PlacedID: i64ValOrZero(raw[25]),
}
if len(raw) >= 31 {
o.Meta = siMapOrNil(raw[31])
}
}

return
return o, nil
}

// OrderSnapshotFromRaw takes a raw list of values as returned from the websocket
Expand Down