mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-16 17:12:25 +08:00
feat(trader): implement margin mode handling for order and leverage settings
This commit is contained in:
162
trader/okx/trader_margin_mode_test.go
Normal file
162
trader/okx/trader_margin_mode_test.go
Normal file
@@ -0,0 +1,162 @@
|
||||
package okx
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"nofx/trader/types"
|
||||
)
|
||||
|
||||
type capturedRequest struct {
|
||||
Method string
|
||||
Path string
|
||||
Body map[string]interface{}
|
||||
}
|
||||
|
||||
type recordingTransport struct {
|
||||
requests []capturedRequest
|
||||
}
|
||||
|
||||
func (rt *recordingTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
var body map[string]interface{}
|
||||
if req.Body != nil {
|
||||
data, _ := io.ReadAll(req.Body)
|
||||
if len(data) > 0 && strings.HasPrefix(strings.TrimSpace(string(data)), "{") {
|
||||
_ = json.Unmarshal(data, &body)
|
||||
}
|
||||
}
|
||||
|
||||
rt.requests = append(rt.requests, capturedRequest{
|
||||
Method: req.Method,
|
||||
Path: req.URL.Path,
|
||||
Body: body,
|
||||
})
|
||||
|
||||
response := `{"code":"0","msg":"","data":[]}`
|
||||
switch req.URL.Path {
|
||||
case okxInstrumentsPath:
|
||||
response = `{"code":"0","msg":"","data":[{"instId":"BTC-USDT-SWAP","ctVal":"0.01","ctMult":"1","lotSz":"1","minSz":"1","maxMktSz":"100000","tickSz":"0.1","ctType":"linear"}]}`
|
||||
case okxOrderPath:
|
||||
response = `{"code":"0","msg":"","data":[{"ordId":"123","clOrdId":"abc","sCode":"0","sMsg":""}]}`
|
||||
}
|
||||
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Header: make(http.Header),
|
||||
Body: io.NopCloser(bytes.NewBufferString(response)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (rt *recordingTransport) requestsForPath(path string) []capturedRequest {
|
||||
var matches []capturedRequest
|
||||
for _, req := range rt.requests {
|
||||
if req.Path == path {
|
||||
matches = append(matches, req)
|
||||
}
|
||||
}
|
||||
return matches
|
||||
}
|
||||
|
||||
func newTestOKXTrader(rt *recordingTransport, isCrossMargin bool) *OKXTrader {
|
||||
return &OKXTrader{
|
||||
apiKey: "key",
|
||||
secretKey: "secret",
|
||||
passphrase: "pass",
|
||||
isCrossMargin: isCrossMargin,
|
||||
positionMode: "long_short_mode",
|
||||
httpClient: &http.Client{
|
||||
Transport: rt,
|
||||
},
|
||||
cacheDuration: 15 * time.Second,
|
||||
instrumentsCache: make(map[string]*OKXInstrument),
|
||||
instrumentsCacheTime: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
func TestOKXSetLeverageUsesConfiguredMarginMode(t *testing.T) {
|
||||
rt := &recordingTransport{}
|
||||
trader := newTestOKXTrader(rt, false)
|
||||
|
||||
if err := trader.SetLeverage("BTCUSDT", 5); err != nil {
|
||||
t.Fatalf("SetLeverage failed: %v", err)
|
||||
}
|
||||
|
||||
leverageRequests := rt.requestsForPath(okxLeveragePath)
|
||||
if len(leverageRequests) != 2 {
|
||||
t.Fatalf("expected 2 leverage requests, got %d", len(leverageRequests))
|
||||
}
|
||||
|
||||
for _, req := range leverageRequests {
|
||||
if req.Body["mgnMode"] != "isolated" {
|
||||
t.Fatalf("expected isolated leverage mode, got %#v", req.Body["mgnMode"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOKXOpenLongUsesConfiguredMarginMode(t *testing.T) {
|
||||
rt := &recordingTransport{}
|
||||
trader := newTestOKXTrader(rt, false)
|
||||
|
||||
if _, err := trader.OpenLong("BTCUSDT", 0.1, 5); err != nil {
|
||||
t.Fatalf("OpenLong failed: %v", err)
|
||||
}
|
||||
|
||||
orderRequests := rt.requestsForPath(okxOrderPath)
|
||||
if len(orderRequests) == 0 {
|
||||
t.Fatal("expected at least one order request")
|
||||
}
|
||||
|
||||
lastOrder := orderRequests[len(orderRequests)-1]
|
||||
if lastOrder.Body["tdMode"] != "isolated" {
|
||||
t.Fatalf("expected isolated tdMode, got %#v", lastOrder.Body["tdMode"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestOKXSetStopLossUsesConfiguredMarginMode(t *testing.T) {
|
||||
rt := &recordingTransport{}
|
||||
trader := newTestOKXTrader(rt, false)
|
||||
|
||||
if err := trader.SetStopLoss("BTCUSDT", "LONG", 0.1, 90000); err != nil {
|
||||
t.Fatalf("SetStopLoss failed: %v", err)
|
||||
}
|
||||
|
||||
algoRequests := rt.requestsForPath(okxAlgoOrderPath)
|
||||
if len(algoRequests) != 1 {
|
||||
t.Fatalf("expected 1 algo order request, got %d", len(algoRequests))
|
||||
}
|
||||
|
||||
if algoRequests[0].Body["tdMode"] != "isolated" {
|
||||
t.Fatalf("expected isolated tdMode, got %#v", algoRequests[0].Body["tdMode"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestOKXPlaceLimitOrderUsesConfiguredMarginMode(t *testing.T) {
|
||||
rt := &recordingTransport{}
|
||||
trader := newTestOKXTrader(rt, false)
|
||||
|
||||
_, err := trader.PlaceLimitOrder(&types.LimitOrderRequest{
|
||||
Symbol: "BTCUSDT",
|
||||
Side: "BUY",
|
||||
PositionSide: "LONG",
|
||||
Price: 95000,
|
||||
Quantity: 0.1,
|
||||
Leverage: 3,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("PlaceLimitOrder failed: %v", err)
|
||||
}
|
||||
|
||||
orderRequests := rt.requestsForPath(okxOrderPath)
|
||||
if len(orderRequests) != 1 {
|
||||
t.Fatalf("expected 1 limit order request, got %d", len(orderRequests))
|
||||
}
|
||||
|
||||
if orderRequests[0].Body["tdMode"] != "isolated" {
|
||||
t.Fatalf("expected isolated tdMode, got %#v", orderRequests[0].Body["tdMode"])
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user