mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-06-06 23:16:53 +00:00
Binance,Okx: Add Leverage, MarginType, Positions and CollateralMode support (#1220)
* init * surprise train commit * basic distinctions * the terms of binance are confusing * renames and introduction of allocatedMargin * add new margin funcs * pulling out wires * implement proper getposition stuff * bad coding day * investigate order manager next * a broken mess, but a progressing one * finally completes some usdtmargined stuff * coinMfutures eludes me * expand to okx * imports fix * completes okx wrapper implementations * cleans and polishes before rpc implementations * rpc setup, order manager features, exch features * more rpc, collateral and margin things * mini test * looking at rpc response, expansion of features * reorganising before the storm * changing how futures requests work * cleanup and tests of cli usage * remove silly client side logic * cleanup * collateral package, typo fix, margin err, rpc derive * uses convert.StringToFloat ONLY ON STRUCTS FROM THIS PR * fix binance order history bug * niteroos * adds new funcs to exchange standards testing * more post merge fixes * fix binance * replace simepletimeformat * fix for merge * merge fixes * micro fixes * order side now required for leverage * fix up the rest * global -> portfolio collateral * Update exchanges/collateral/collateral_test.go Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io> * adds fields and todos * rm field redundancy * lint fix oopsie daisy * fixes panic, expands error and cli explanations (sorry shaz) * ensures casing is appropriate for underlying * Adds a shiny TODO --------- Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/shopspring/decimal"
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/communications/base"
|
||||
"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/asset"
|
||||
@@ -24,7 +25,7 @@ import (
|
||||
)
|
||||
|
||||
// SetupOrderManager will boot up the OrderManager
|
||||
func SetupOrderManager(exchangeManager iExchangeManager, communicationsManager iCommsManager, wg *sync.WaitGroup, verbose, activelyTrackFuturesPositions bool, futuresTrackingSeekDuration time.Duration) (*OrderManager, error) {
|
||||
func SetupOrderManager(exchangeManager iExchangeManager, communicationsManager iCommsManager, wg *sync.WaitGroup, cfg *config.OrderManager) (*OrderManager, error) {
|
||||
if exchangeManager == nil {
|
||||
return nil, errNilExchangeManager
|
||||
}
|
||||
@@ -34,10 +35,18 @@ func SetupOrderManager(exchangeManager iExchangeManager, communicationsManager i
|
||||
if wg == nil {
|
||||
return nil, errNilWaitGroup
|
||||
}
|
||||
if cfg == nil {
|
||||
return nil, fmt.Errorf("%w OrderManager", errNilConfig)
|
||||
}
|
||||
|
||||
var respectOrderHistoryLimits bool
|
||||
if cfg.RespectOrderHistoryLimits != nil {
|
||||
respectOrderHistoryLimits = *cfg.RespectOrderHistoryLimits
|
||||
}
|
||||
om := &OrderManager{
|
||||
shutdown: make(chan struct{}),
|
||||
activelyTrackFuturesPositions: activelyTrackFuturesPositions,
|
||||
activelyTrackFuturesPositions: cfg.ActivelyTrackFuturesPositions,
|
||||
respectOrderHistoryLimits: respectOrderHistoryLimits,
|
||||
orderStore: store{
|
||||
Orders: make(map[string][]*order.Detail),
|
||||
exchangeManager: exchangeManager,
|
||||
@@ -45,16 +54,19 @@ func SetupOrderManager(exchangeManager iExchangeManager, communicationsManager i
|
||||
wg: wg,
|
||||
futuresPositionController: order.SetupPositionController(),
|
||||
},
|
||||
verbose: verbose,
|
||||
verbose: cfg.Verbose,
|
||||
cfg: orderManagerConfig{
|
||||
CancelOrdersOnShutdown: cfg.CancelOrdersOnShutdown,
|
||||
},
|
||||
}
|
||||
if activelyTrackFuturesPositions {
|
||||
if futuresTrackingSeekDuration > 0 {
|
||||
futuresTrackingSeekDuration = -futuresTrackingSeekDuration
|
||||
if cfg.ActivelyTrackFuturesPositions {
|
||||
if cfg.FuturesTrackingSeekDuration > 0 {
|
||||
cfg.FuturesTrackingSeekDuration *= -1
|
||||
}
|
||||
if futuresTrackingSeekDuration == 0 {
|
||||
futuresTrackingSeekDuration = defaultOrderSeekTime
|
||||
if cfg.FuturesTrackingSeekDuration == 0 {
|
||||
cfg.FuturesTrackingSeekDuration = defaultOrderSeekTime
|
||||
}
|
||||
om.futuresPositionSeekDuration = futuresTrackingSeekDuration
|
||||
om.futuresPositionSeekDuration = cfg.FuturesTrackingSeekDuration
|
||||
}
|
||||
return om, nil
|
||||
}
|
||||
@@ -699,9 +711,9 @@ func (m *OrderManager) processOrders() {
|
||||
wg.Add(1)
|
||||
go m.processMatchingOrders(exchanges[x], orders, &wg)
|
||||
}
|
||||
|
||||
if m.activelyTrackFuturesPositions && enabledAssets[y].IsFutures() {
|
||||
var positions []order.PositionDetails
|
||||
supportedFeatures := exchanges[x].GetSupportedFeatures()
|
||||
if m.activelyTrackFuturesPositions && enabledAssets[y].IsFutures() && supportedFeatures.FuturesCapabilities.OrderManagerPositionTracking {
|
||||
var positions []order.PositionResponse
|
||||
var sd time.Time
|
||||
sd, err = m.orderStore.futuresPositionController.LastUpdated()
|
||||
if err != nil {
|
||||
@@ -711,10 +723,11 @@ func (m *OrderManager) processOrders() {
|
||||
if sd.IsZero() {
|
||||
sd = time.Now().Add(m.futuresPositionSeekDuration)
|
||||
}
|
||||
positions, err = exchanges[x].GetFuturesPositions(context.TODO(), &order.PositionsRequest{
|
||||
Asset: enabledAssets[y],
|
||||
Pairs: pairs,
|
||||
StartDate: sd,
|
||||
positions, err = exchanges[x].GetFuturesPositionOrders(context.TODO(), &order.PositionsRequest{
|
||||
Asset: enabledAssets[y],
|
||||
Pairs: pairs,
|
||||
StartDate: sd,
|
||||
RespectOrderHistoryLimits: m.respectOrderHistoryLimits,
|
||||
})
|
||||
if err != nil {
|
||||
if !errors.Is(err, common.ErrNotYetImplemented) {
|
||||
@@ -728,7 +741,7 @@ func (m *OrderManager) processOrders() {
|
||||
}
|
||||
err = m.processFuturesPositions(exchanges[x], &positions[z])
|
||||
if err != nil {
|
||||
log.Errorf(log.OrderMgr, "unable to process future positions for %v %v %v. err: %v", positions[z].Exchange, positions[z].Asset, positions[z].Pair, err)
|
||||
log.Errorf(log.OrderMgr, "unable to process future positions for %v %v %v. err: %v", exchanges[x].GetName(), positions[z].Asset, positions[z].Pair, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -741,7 +754,7 @@ func (m *OrderManager) processOrders() {
|
||||
}
|
||||
|
||||
// processFuturesPositions ensures any open position found is kept up to date in the order manager
|
||||
func (m *OrderManager) processFuturesPositions(exch exchange.IBotExchange, position *order.PositionDetails) error {
|
||||
func (m *OrderManager) processFuturesPositions(exch exchange.IBotExchange, position *order.PositionResponse) error {
|
||||
if !m.activelyTrackFuturesPositions {
|
||||
return errFuturesTrackingDisabled
|
||||
}
|
||||
@@ -749,14 +762,15 @@ func (m *OrderManager) processFuturesPositions(exch exchange.IBotExchange, posit
|
||||
return fmt.Errorf("%w IBotExchange", common.ErrNilPointer)
|
||||
}
|
||||
if position == nil {
|
||||
return fmt.Errorf("%w PositionDetails", common.ErrNilPointer)
|
||||
return fmt.Errorf("%w PositionResponse", common.ErrNilPointer)
|
||||
}
|
||||
if len(position.Orders) == 0 {
|
||||
return fmt.Errorf("%w position for '%v' '%v' '%v' has no orders", errNilOrder, position.Exchange, position.Asset, position.Pair)
|
||||
return fmt.Errorf("%w position for '%v' '%v' '%v' has no orders", errNilOrder, exch.GetName(), position.Asset, position.Pair)
|
||||
}
|
||||
sort.Slice(position.Orders, func(i, j int) bool {
|
||||
return position.Orders[i].Date.Before(position.Orders[j].Date)
|
||||
})
|
||||
feat := exch.GetSupportedFeatures()
|
||||
var err error
|
||||
for i := range position.Orders {
|
||||
err = m.orderStore.futuresPositionController.TrackNewOrder(&position.Orders[i])
|
||||
@@ -764,7 +778,7 @@ func (m *OrderManager) processFuturesPositions(exch exchange.IBotExchange, posit
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = m.orderStore.futuresPositionController.GetOpenPosition(position.Exchange, position.Asset, position.Pair)
|
||||
_, err = m.orderStore.futuresPositionController.GetOpenPosition(exch.GetName(), position.Asset, position.Pair)
|
||||
if err != nil {
|
||||
if errors.Is(err, order.ErrPositionNotFound) {
|
||||
return nil
|
||||
@@ -773,11 +787,14 @@ func (m *OrderManager) processFuturesPositions(exch exchange.IBotExchange, posit
|
||||
}
|
||||
tick, err := exch.FetchTicker(context.TODO(), position.Pair, position.Asset)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w when fetching ticker data for %v %v %v", err, position.Exchange, position.Asset, position.Pair)
|
||||
return fmt.Errorf("%w when fetching ticker data for %v %v %v", err, exch.GetName(), position.Asset, position.Pair)
|
||||
}
|
||||
_, err = m.UpdateOpenPositionUnrealisedPNL(position.Exchange, position.Asset, position.Pair, tick.Last, tick.LastUpdated)
|
||||
_, err = m.UpdateOpenPositionUnrealisedPNL(exch.GetName(), position.Asset, position.Pair, tick.Last, tick.LastUpdated)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w when updating unrealised PNL for %v %v %v", err, position.Exchange, position.Asset, position.Pair)
|
||||
return fmt.Errorf("%w when updating unrealised PNL for %v %v %v", err, exch.GetName(), position.Asset, position.Pair)
|
||||
}
|
||||
if !feat.FuturesCapabilities.FundingRates {
|
||||
return nil
|
||||
}
|
||||
isPerp, err := exch.IsPerpetualFutureCurrency(position.Asset, position.Pair)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user