From d799cf79c2309bba795b315e8c213991b754a10f Mon Sep 17 00:00:00 2001 From: discountry Date: Mon, 6 Apr 2026 18:24:42 +0800 Subject: [PATCH] refactor: extract shared order handler factory, deduplicate 8 order.ts files Created src/exchanges/order-handlers.ts with createOrderHandlers() factory. All 8 exchange order.ts files now use config-driven delegation instead of duplicated ~80-line implementations. Shared applyCommonFields() logic consolidated into the factory module. --- src/exchanges/aster/order.ts | 112 ++++--------------------- src/exchanges/backpack/order.ts | 96 ++++----------------- src/exchanges/binance/order.ts | 112 ++++--------------------- src/exchanges/grvt/order.ts | 107 ++++-------------------- src/exchanges/lighter/order.ts | 109 +++++------------------- src/exchanges/nado/order.ts | 109 +++++------------------- src/exchanges/order-handlers.ts | 144 ++++++++++++++++++++++++++++++++ src/exchanges/paradex/order.ts | 109 ++++-------------------- src/exchanges/standx/order.ts | 111 +++++------------------- 9 files changed, 279 insertions(+), 730 deletions(-) create mode 100644 src/exchanges/order-handlers.ts diff --git a/src/exchanges/aster/order.ts b/src/exchanges/aster/order.ts index e1a963c..028b012 100644 --- a/src/exchanges/aster/order.ts +++ b/src/exchanges/aster/order.ts @@ -1,101 +1,17 @@ -import type { Order, CreateOrderParams } from "../types"; -import type { - BaseOrderIntent, - ClosePositionIntent, - LimitOrderIntent, - MarketOrderIntent, - StopOrderIntent, - TrailingStopOrderIntent, -} from "../order-schema"; -import { toStringBoolean } from "../order-schema"; +import { createOrderHandlers } from "../order-handlers"; -function applyCommonFields(params: CreateOrderParams, intent: BaseOrderIntent): CreateOrderParams { - if (params.quantity === undefined) { - params.quantity = intent.quantity; - } - if (params.timeInForce === undefined && intent.timeInForce) { - params.timeInForce = intent.timeInForce; - } - if (intent.reduceOnly !== undefined) { - params.reduceOnly = toStringBoolean(intent.reduceOnly); - } - if (intent.closePosition !== undefined) { - params.closePosition = toStringBoolean(intent.closePosition); - } - return params; -} +const handlers = createOrderHandlers({ + exchangeName: "Aster", + defaultLimitTimeInForce: "GTX", + supportsTrailingStop: true, + supportsTriggerType: true, +}); -export async function createLimitOrder(intent: LimitOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "LIMIT", - quantity: intent.quantity, - price: intent.price, - timeInForce: intent.timeInForce ?? "GTX", - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createMarketOrder(intent: MarketOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "MARKET", - quantity: intent.quantity, - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createStopOrder(intent: StopOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "STOP_MARKET", - quantity: intent.quantity, - stopPrice: intent.stopPrice, - timeInForce: intent.timeInForce ?? "GTC", - triggerType: intent.triggerType, - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createTrailingStopOrder(intent: TrailingStopOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "TRAILING_STOP_MARKET", - quantity: intent.quantity, - activationPrice: intent.activationPrice, - callbackRate: intent.callbackRate, - timeInForce: intent.timeInForce ?? "GTC", - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createClosePositionOrder(intent: ClosePositionIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "MARKET", - quantity: intent.quantity, - reduceOnly: "true", - }, - intent - ); - return intent.adapter.createOrder(params); -} +export const { + createLimitOrder, + createMarketOrder, + createStopOrder, + createTrailingStopOrder, + createClosePositionOrder, +} = handlers; diff --git a/src/exchanges/backpack/order.ts b/src/exchanges/backpack/order.ts index b0b4e13..cad379c 100644 --- a/src/exchanges/backpack/order.ts +++ b/src/exchanges/backpack/order.ts @@ -1,84 +1,16 @@ -import type { Order, CreateOrderParams } from "../types"; -import type { - BaseOrderIntent, - ClosePositionIntent, - LimitOrderIntent, - MarketOrderIntent, - StopOrderIntent, - TrailingStopOrderIntent, -} from "../order-schema"; -import { toStringBoolean } from "../order-schema"; +import { createOrderHandlers } from "../order-handlers"; -function applyCommonFields(params: CreateOrderParams, intent: BaseOrderIntent): CreateOrderParams { - if (params.quantity === undefined) { - params.quantity = intent.quantity; - } - if (params.timeInForce === undefined && intent.timeInForce) { - params.timeInForce = intent.timeInForce; - } - if (intent.reduceOnly !== undefined) { - params.reduceOnly = toStringBoolean(intent.reduceOnly); - } - return params; -} +const handlers = createOrderHandlers({ + exchangeName: "Backpack", + defaultLimitTimeInForce: "GTX", + supportsTrailingStop: false, + supportsTriggerType: false, +}); -export async function createLimitOrder(intent: LimitOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "LIMIT", - quantity: intent.quantity, - price: intent.price, - timeInForce: intent.timeInForce ?? "GTX", - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createMarketOrder(intent: MarketOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "MARKET", - quantity: intent.quantity, - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createStopOrder(intent: StopOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "STOP_MARKET", - quantity: intent.quantity, - stopPrice: intent.stopPrice, - timeInForce: intent.timeInForce ?? "GTC", - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createTrailingStopOrder(_intent: TrailingStopOrderIntent): Promise { - throw new Error("Backpack exchange does not support trailing stop orders"); -} - -export async function createClosePositionOrder(intent: ClosePositionIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "MARKET", - quantity: intent.quantity, - reduceOnly: "true", - }, - intent - ); - return intent.adapter.createOrder(params); -} +export const { + createLimitOrder, + createMarketOrder, + createStopOrder, + createTrailingStopOrder, + createClosePositionOrder, +} = handlers; diff --git a/src/exchanges/binance/order.ts b/src/exchanges/binance/order.ts index f9c6404..f4d7e72 100644 --- a/src/exchanges/binance/order.ts +++ b/src/exchanges/binance/order.ts @@ -1,100 +1,16 @@ -import type { Order, CreateOrderParams } from "../types"; -import type { - BaseOrderIntent, - ClosePositionIntent, - LimitOrderIntent, - MarketOrderIntent, - StopOrderIntent, - TrailingStopOrderIntent, -} from "../order-schema"; -import { toStringBoolean } from "../order-schema"; +import { createOrderHandlers } from "../order-handlers"; -function applyCommonFields(params: CreateOrderParams, intent: BaseOrderIntent): CreateOrderParams { - if (params.quantity === undefined) { - params.quantity = intent.quantity; - } - if (params.timeInForce === undefined && intent.timeInForce) { - params.timeInForce = intent.timeInForce; - } - if (intent.reduceOnly !== undefined) { - params.reduceOnly = toStringBoolean(intent.reduceOnly); - } - if (intent.closePosition !== undefined) { - params.closePosition = toStringBoolean(intent.closePosition); - } - return params; -} +const handlers = createOrderHandlers({ + exchangeName: "Binance", + defaultLimitTimeInForce: "GTX", + supportsTrailingStop: true, + supportsTriggerType: true, +}); -export async function createLimitOrder(intent: LimitOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "LIMIT", - quantity: intent.quantity, - price: intent.price, - timeInForce: intent.timeInForce ?? "GTX", - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createMarketOrder(intent: MarketOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "MARKET", - quantity: intent.quantity, - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createStopOrder(intent: StopOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "STOP_MARKET", - quantity: intent.quantity, - stopPrice: intent.stopPrice, - timeInForce: intent.timeInForce ?? "GTC", - triggerType: intent.triggerType, - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createTrailingStopOrder(intent: TrailingStopOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "TRAILING_STOP_MARKET", - quantity: intent.quantity, - activationPrice: intent.activationPrice, - callbackRate: intent.callbackRate, - timeInForce: intent.timeInForce ?? "GTC", - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createClosePositionOrder(intent: ClosePositionIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "MARKET", - quantity: intent.quantity, - reduceOnly: "true", - }, - intent - ); - return intent.adapter.createOrder(params); -} +export const { + createLimitOrder, + createMarketOrder, + createStopOrder, + createTrailingStopOrder, + createClosePositionOrder, +} = handlers; diff --git a/src/exchanges/grvt/order.ts b/src/exchanges/grvt/order.ts index 0036874..62531f5 100644 --- a/src/exchanges/grvt/order.ts +++ b/src/exchanges/grvt/order.ts @@ -1,92 +1,21 @@ -import type { Order, CreateOrderParams } from "../types"; -import type { - BaseOrderIntent, - ClosePositionIntent, - LimitOrderIntent, - MarketOrderIntent, - StopOrderIntent, - TrailingStopOrderIntent, -} from "../order-schema"; -import { toStringBoolean } from "../order-schema"; +import { createOrderHandlers } from "../order-handlers"; -function applyCommonFields(params: CreateOrderParams, intent: BaseOrderIntent): CreateOrderParams { - if (params.quantity === undefined) { - params.quantity = intent.quantity; - } - if (params.timeInForce === undefined && intent.timeInForce) { - params.timeInForce = intent.timeInForce; - } - if (intent.reduceOnly !== undefined) { - params.reduceOnly = toStringBoolean(intent.reduceOnly); - } - if (intent.closePosition !== undefined) { - params.closePosition = toStringBoolean(intent.closePosition); - } - return params; -} +const handlers = createOrderHandlers({ + exchangeName: "GRVT", + defaultLimitTimeInForce: "GTX", + supportsTrailingStop: false, + supportsTriggerType: true, + defaultStopTriggerType: "STOP_LOSS", + stopDefaultReduceOnly: true, + stopDefaultClosePosition: true, + closeDefaultClosePosition: true, +}); -export async function createLimitOrder(intent: LimitOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "LIMIT", - quantity: intent.quantity, - price: intent.price, - timeInForce: intent.timeInForce ?? "GTX", - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createMarketOrder(intent: MarketOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "MARKET", - quantity: intent.quantity, - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createStopOrder(intent: StopOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "STOP_MARKET", - quantity: intent.quantity, - stopPrice: intent.stopPrice, - timeInForce: intent.timeInForce ?? "GTC", - triggerType: intent.triggerType ?? "STOP_LOSS", - closePosition: toStringBoolean(intent.closePosition ?? true), - reduceOnly: toStringBoolean(intent.reduceOnly ?? true), - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createTrailingStopOrder(_intent: TrailingStopOrderIntent): Promise { - throw new Error("GRVT exchange does not support trailing stop orders"); -} - -export async function createClosePositionOrder(intent: ClosePositionIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "MARKET", - quantity: intent.quantity, - reduceOnly: "true", - closePosition: toStringBoolean(intent.closePosition ?? true), - }, - intent - ); - return intent.adapter.createOrder(params); -} +export const { + createLimitOrder, + createMarketOrder, + createStopOrder, + createTrailingStopOrder, + createClosePositionOrder, +} = handlers; diff --git a/src/exchanges/lighter/order.ts b/src/exchanges/lighter/order.ts index 735b298..728a494 100644 --- a/src/exchanges/lighter/order.ts +++ b/src/exchanges/lighter/order.ts @@ -1,93 +1,22 @@ -import type { Order, CreateOrderParams } from "../types"; -import type { - BaseOrderIntent, - ClosePositionIntent, - LimitOrderIntent, - MarketOrderIntent, - StopOrderIntent, - TrailingStopOrderIntent, -} from "../order-schema"; -import { toStringBoolean } from "../order-schema"; +import { createOrderHandlers } from "../order-handlers"; -function applyCommonFields(params: CreateOrderParams, intent: BaseOrderIntent): CreateOrderParams { - if (params.quantity === undefined) { - params.quantity = intent.quantity; - } - if (params.timeInForce === undefined && intent.timeInForce) { - params.timeInForce = intent.timeInForce; - } - if (intent.reduceOnly !== undefined) { - params.reduceOnly = toStringBoolean(intent.reduceOnly); - } - if (intent.closePosition !== undefined) { - params.closePosition = toStringBoolean(intent.closePosition); - } - return params; -} +const handlers = createOrderHandlers({ + exchangeName: "Lighter", + defaultLimitTimeInForce: "GTC", + defaultMarketTimeInForce: "IOC", + defaultCloseTimeInForce: "IOC", + supportsTrailingStop: false, + supportsTriggerType: false, + stopDefaultReduceOnly: true, + stopDefaultClosePosition: true, + closeDefaultClosePosition: true, +}); -export async function createLimitOrder(intent: LimitOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "LIMIT", - quantity: intent.quantity, - price: intent.price, - timeInForce: intent.timeInForce ?? "GTC", - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createMarketOrder(intent: MarketOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "MARKET", - quantity: intent.quantity, - timeInForce: intent.timeInForce ?? "IOC", - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createStopOrder(intent: StopOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "STOP_MARKET", - quantity: intent.quantity, - stopPrice: intent.stopPrice, - timeInForce: intent.timeInForce ?? "GTC", - reduceOnly: toStringBoolean(intent.reduceOnly ?? true), - closePosition: toStringBoolean(intent.closePosition ?? true), - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createTrailingStopOrder(_intent: TrailingStopOrderIntent): Promise { - throw new Error("Lighter exchange does not support trailing stop orders"); -} - -export async function createClosePositionOrder(intent: ClosePositionIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "MARKET", - quantity: intent.quantity, - reduceOnly: "true", - closePosition: toStringBoolean(intent.closePosition ?? true), - timeInForce: intent.timeInForce ?? "IOC", - }, - intent - ); - return intent.adapter.createOrder(params); -} +export const { + createLimitOrder, + createMarketOrder, + createStopOrder, + createTrailingStopOrder, + createClosePositionOrder, +} = handlers; diff --git a/src/exchanges/nado/order.ts b/src/exchanges/nado/order.ts index 5d9ef0e..aef8ca0 100644 --- a/src/exchanges/nado/order.ts +++ b/src/exchanges/nado/order.ts @@ -1,93 +1,22 @@ -import type { Order, CreateOrderParams } from "../types"; -import type { - BaseOrderIntent, - ClosePositionIntent, - LimitOrderIntent, - MarketOrderIntent, - StopOrderIntent, - TrailingStopOrderIntent, -} from "../order-schema"; -import { toStringBoolean } from "../order-schema"; +import { createOrderHandlers } from "../order-handlers"; -function applyCommonFields(params: CreateOrderParams, intent: BaseOrderIntent): CreateOrderParams { - if (params.quantity === undefined) { - params.quantity = intent.quantity; - } - if (params.timeInForce === undefined && intent.timeInForce) { - params.timeInForce = intent.timeInForce; - } - if (intent.reduceOnly !== undefined) { - params.reduceOnly = toStringBoolean(intent.reduceOnly); - } - if (intent.closePosition !== undefined) { - params.closePosition = toStringBoolean(intent.closePosition); - } - return params; -} +const handlers = createOrderHandlers({ + exchangeName: "Nado", + defaultLimitTimeInForce: "GTC", + defaultMarketTimeInForce: "IOC", + defaultCloseTimeInForce: "IOC", + supportsTrailingStop: false, + supportsTriggerType: false, + stopDefaultReduceOnly: true, + stopDefaultClosePosition: true, + closeDefaultClosePosition: true, +}); -export async function createLimitOrder(intent: LimitOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "LIMIT", - quantity: intent.quantity, - price: intent.price, - timeInForce: intent.timeInForce ?? "GTC", - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createMarketOrder(intent: MarketOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "MARKET", - quantity: intent.quantity, - timeInForce: intent.timeInForce ?? "IOC", - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createStopOrder(intent: StopOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "STOP_MARKET", - quantity: intent.quantity, - stopPrice: intent.stopPrice, - timeInForce: intent.timeInForce ?? "GTC", - reduceOnly: toStringBoolean(intent.reduceOnly ?? true), - closePosition: toStringBoolean(intent.closePosition ?? true), - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createTrailingStopOrder(_intent: TrailingStopOrderIntent): Promise { - throw new Error("Nado exchange does not support trailing stop orders"); -} - -export async function createClosePositionOrder(intent: ClosePositionIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "MARKET", - quantity: intent.quantity, - reduceOnly: "true", - closePosition: toStringBoolean(intent.closePosition ?? true), - timeInForce: intent.timeInForce ?? "IOC", - }, - intent - ); - return intent.adapter.createOrder(params); -} +export const { + createLimitOrder, + createMarketOrder, + createStopOrder, + createTrailingStopOrder, + createClosePositionOrder, +} = handlers; diff --git a/src/exchanges/order-handlers.ts b/src/exchanges/order-handlers.ts new file mode 100644 index 0000000..975e7ce --- /dev/null +++ b/src/exchanges/order-handlers.ts @@ -0,0 +1,144 @@ +import type { Order, CreateOrderParams, TimeInForce } from "./types"; +import type { + BaseOrderIntent, + ClosePositionIntent, + LimitOrderIntent, + MarketOrderIntent, + StopOrderIntent, + TrailingStopOrderIntent, +} from "./order-schema"; +import { toStringBoolean } from "./order-schema"; + +export interface OrderHandlerConfig { + exchangeName: string; + defaultLimitTimeInForce: TimeInForce | "GTX"; + defaultMarketTimeInForce?: TimeInForce; + defaultCloseTimeInForce?: TimeInForce; + defaultStopTimeInForce?: TimeInForce; + defaultStopTriggerType?: "UNSPECIFIED" | "TAKE_PROFIT" | "STOP_LOSS"; + supportsTrailingStop: boolean; + supportsTriggerType: boolean; + stopDefaultReduceOnly?: boolean; + stopDefaultClosePosition?: boolean; + closeDefaultClosePosition?: boolean; + stopPriceAsPrice?: boolean; +} + +export interface OrderHandlers { + createLimitOrder(intent: LimitOrderIntent): Promise; + createMarketOrder(intent: MarketOrderIntent): Promise; + createStopOrder(intent: StopOrderIntent): Promise; + createTrailingStopOrder(intent: TrailingStopOrderIntent): Promise; + createClosePositionOrder(intent: ClosePositionIntent): Promise; +} + +function applyCommonFields(params: CreateOrderParams, intent: BaseOrderIntent): CreateOrderParams { + if (params.quantity === undefined) { + params.quantity = intent.quantity; + } + if (params.timeInForce === undefined && intent.timeInForce) { + params.timeInForce = intent.timeInForce; + } + if (intent.reduceOnly !== undefined) { + params.reduceOnly = toStringBoolean(intent.reduceOnly); + } + if (intent.closePosition !== undefined) { + params.closePosition = toStringBoolean(intent.closePosition); + } + return params; +} + +export function createOrderHandlers(config: OrderHandlerConfig): OrderHandlers { + return { + async createLimitOrder(intent: LimitOrderIntent): Promise { + const params: CreateOrderParams = applyCommonFields( + { + symbol: intent.symbol, + side: intent.side, + type: "LIMIT", + quantity: intent.quantity, + price: intent.price, + timeInForce: intent.timeInForce ?? config.defaultLimitTimeInForce, + slPrice: intent.slPrice, + tpPrice: intent.tpPrice, + }, + intent, + ); + return intent.adapter.createOrder(params); + }, + + async createMarketOrder(intent: MarketOrderIntent): Promise { + const params: CreateOrderParams = applyCommonFields( + { + symbol: intent.symbol, + side: intent.side, + type: "MARKET", + quantity: intent.quantity, + timeInForce: intent.timeInForce ?? config.defaultMarketTimeInForce, + }, + intent, + ); + return intent.adapter.createOrder(params); + }, + + async createStopOrder(intent: StopOrderIntent): Promise { + const params: CreateOrderParams = applyCommonFields( + { + symbol: intent.symbol, + side: intent.side, + type: "STOP_MARKET", + quantity: intent.quantity, + stopPrice: intent.stopPrice, + timeInForce: intent.timeInForce ?? (config.defaultStopTimeInForce ?? "GTC"), + triggerType: config.supportsTriggerType ? (intent.triggerType ?? config.defaultStopTriggerType) : undefined, + price: config.stopPriceAsPrice ? intent.stopPrice : undefined, + }, + intent, + ); + if (config.stopDefaultReduceOnly && intent.reduceOnly === undefined) { + params.reduceOnly = "true"; + } + if (config.stopDefaultClosePosition && intent.closePosition === undefined) { + params.closePosition = "true"; + } + return intent.adapter.createOrder(params); + }, + + async createTrailingStopOrder(intent: TrailingStopOrderIntent): Promise { + if (!config.supportsTrailingStop) { + throw new Error(`${config.exchangeName} does not support trailing stop orders`); + } + const params: CreateOrderParams = applyCommonFields( + { + symbol: intent.symbol, + side: intent.side, + type: "TRAILING_STOP_MARKET", + quantity: intent.quantity, + activationPrice: intent.activationPrice, + callbackRate: intent.callbackRate, + timeInForce: intent.timeInForce ?? "GTC", + }, + intent, + ); + return intent.adapter.createOrder(params); + }, + + async createClosePositionOrder(intent: ClosePositionIntent): Promise { + const params: CreateOrderParams = applyCommonFields( + { + symbol: intent.symbol, + side: intent.side, + type: "MARKET", + quantity: intent.quantity, + reduceOnly: "true", + timeInForce: intent.timeInForce ?? config.defaultCloseTimeInForce, + }, + intent, + ); + if (config.closeDefaultClosePosition && intent.closePosition === undefined) { + params.closePosition = "true"; + } + return intent.adapter.createOrder(params); + }, + }; +} diff --git a/src/exchanges/paradex/order.ts b/src/exchanges/paradex/order.ts index 696de61..31b7d02 100644 --- a/src/exchanges/paradex/order.ts +++ b/src/exchanges/paradex/order.ts @@ -1,93 +1,20 @@ -import type { Order, CreateOrderParams } from "../types"; -import type { - BaseOrderIntent, - ClosePositionIntent, - LimitOrderIntent, - MarketOrderIntent, - StopOrderIntent, - TrailingStopOrderIntent, -} from "../order-schema"; -import { toStringBoolean } from "../order-schema"; +import { createOrderHandlers } from "../order-handlers"; -function applyCommonFields(params: CreateOrderParams, intent: BaseOrderIntent): CreateOrderParams { - if (params.quantity === undefined) { - params.quantity = intent.quantity; - } - if (params.timeInForce === undefined && intent.timeInForce) { - params.timeInForce = intent.timeInForce; - } - if (intent.reduceOnly !== undefined) { - params.reduceOnly = toStringBoolean(intent.reduceOnly); - } - if (intent.closePosition !== undefined) { - params.closePosition = toStringBoolean(intent.closePosition); - } - return params; -} +const handlers = createOrderHandlers({ + exchangeName: "Paradex", + defaultLimitTimeInForce: "GTC", + supportsTrailingStop: false, + supportsTriggerType: false, + stopDefaultReduceOnly: true, + stopDefaultClosePosition: true, + stopPriceAsPrice: true, + closeDefaultClosePosition: true, +}); -export async function createLimitOrder(intent: LimitOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "LIMIT", - quantity: intent.quantity, - price: intent.price, - timeInForce: intent.timeInForce ?? "GTC", - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createMarketOrder(intent: MarketOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "MARKET", - quantity: intent.quantity, - timeInForce: intent.timeInForce, - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createStopOrder(intent: StopOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "STOP_MARKET", - quantity: intent.quantity, - stopPrice: intent.stopPrice, - price: intent.stopPrice, - timeInForce: intent.timeInForce ?? "GTC", - reduceOnly: toStringBoolean(intent.reduceOnly ?? true), - closePosition: toStringBoolean(intent.closePosition ?? true), - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createTrailingStopOrder(_intent: TrailingStopOrderIntent): Promise { - throw new Error("Paradex exchange does not support trailing stop orders"); -} - -export async function createClosePositionOrder(intent: ClosePositionIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "MARKET", - quantity: intent.quantity, - reduceOnly: "true", - closePosition: toStringBoolean(intent.closePosition ?? true), - timeInForce: intent.timeInForce, - }, - intent - ); - return intent.adapter.createOrder(params); -} +export const { + createLimitOrder, + createMarketOrder, + createStopOrder, + createTrailingStopOrder, + createClosePositionOrder, +} = handlers; diff --git a/src/exchanges/standx/order.ts b/src/exchanges/standx/order.ts index 83b914c..129fc75 100644 --- a/src/exchanges/standx/order.ts +++ b/src/exchanges/standx/order.ts @@ -1,94 +1,21 @@ -import type { Order, CreateOrderParams } from "../types"; -import type { - BaseOrderIntent, - ClosePositionIntent, - LimitOrderIntent, - MarketOrderIntent, - StopOrderIntent, - TrailingStopOrderIntent, -} from "../order-schema"; -import { toStringBoolean } from "../order-schema"; +import { createOrderHandlers } from "../order-handlers"; -function applyCommonFields(params: CreateOrderParams, intent: BaseOrderIntent): CreateOrderParams { - if (params.quantity === undefined) { - params.quantity = intent.quantity; - } - if (params.timeInForce === undefined && intent.timeInForce) { - params.timeInForce = intent.timeInForce; - } - if (intent.reduceOnly !== undefined) { - params.reduceOnly = toStringBoolean(intent.reduceOnly); - } - if (intent.closePosition !== undefined) { - params.closePosition = toStringBoolean(intent.closePosition); - } - return params; -} +const handlers = createOrderHandlers({ + exchangeName: "StandX", + defaultLimitTimeInForce: "GTX", + defaultMarketTimeInForce: "IOC", + defaultCloseTimeInForce: "IOC", + supportsTrailingStop: false, + supportsTriggerType: false, + stopDefaultReduceOnly: true, + stopDefaultClosePosition: true, + closeDefaultClosePosition: true, +}); -export async function createLimitOrder(intent: LimitOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "LIMIT", - quantity: intent.quantity, - price: intent.price, - timeInForce: intent.timeInForce ?? "GTX", - slPrice: intent.slPrice, - tpPrice: intent.tpPrice, - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createMarketOrder(intent: MarketOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "MARKET", - quantity: intent.quantity, - timeInForce: intent.timeInForce ?? "IOC", - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createStopOrder(intent: StopOrderIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "STOP_MARKET", - quantity: intent.quantity, - stopPrice: intent.stopPrice, - timeInForce: intent.timeInForce ?? "GTC", - reduceOnly: toStringBoolean(intent.reduceOnly ?? true), - closePosition: toStringBoolean(intent.closePosition ?? true), - }, - intent - ); - return intent.adapter.createOrder(params); -} - -export async function createTrailingStopOrder(_intent: TrailingStopOrderIntent): Promise { - throw new Error("StandX exchange does not support trailing stop orders"); -} - -export async function createClosePositionOrder(intent: ClosePositionIntent): Promise { - const params: CreateOrderParams = applyCommonFields( - { - symbol: intent.symbol, - side: intent.side, - type: "MARKET", - quantity: intent.quantity, - reduceOnly: "true", - closePosition: toStringBoolean(intent.closePosition ?? true), - timeInForce: intent.timeInForce ?? "IOC", - }, - intent - ); - return intent.adapter.createOrder(params); -} +export const { + createLimitOrder, + createMarketOrder, + createStopOrder, + createTrailingStopOrder, + createClosePositionOrder, +} = handlers;