mirror of
https://github.com/laoxong/nofx.git
synced 2026-06-04 09:58:22 +08:00
163 lines
4.2 KiB
Go
163 lines
4.2 KiB
Go
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"])
|
|
}
|
|
}
|