Skip to content

Commit a2fb3b7

Browse files
author
Fernando Fernandes
committed
Add cleaning up logic into trailing stop logic
- Finishes #7 for real this time.
1 parent 83fc825 commit a2fb3b7

File tree

5 files changed

+72
-37
lines changed

5 files changed

+72
-37
lines changed

Sources/SwiftTrader/Model/Error/SwiftTraderError.swift

+25-14
Original file line numberDiff line numberDiff line change
@@ -17,34 +17,45 @@ public enum SwiftTraderError: Error {
1717

1818
// MARK: - Kucoin Related
1919

20+
/// The response status code is something other than `200`.
21+
///
22+
/// The underlying Kucoin system error may be verified by reading the returned extra arguments, if present.
23+
case statusCodeNotOK(
24+
statusCode: Int,
25+
localizedErrorMessage: String,
26+
kucoinErrorCode: String? = nil,
27+
kucoinErrorMessage: String? = nil
28+
)
29+
30+
// MARK: Account Overview
31+
2032
/// And error ocurred while executing the function `SwiftTrader.kucoinFuturesAccountOverview(currencySymbol:)`.
2133
case kucoinFuturesAccountOverview(error: Error)
2234

35+
// MARK: Cancel Stop Orders
36+
2337
/// And error ocurred while executing the function `SwiftTrader.kucoinFuturesCancelStopOrders(symbol:)`.
2438
case kucoinFuturesCancelStopOrders(error: Error)
2539

40+
// MARK: Order
41+
2642
/// Something went wrong while trying to set the target price.
27-
case kucoinCouldNotCalculateTheTargetPrice(input: SwiftTraderOrderInput)
43+
case kucoinCouldNotCalculateTheTargetPrice(input: SwiftTraderStopLimitOrderInput)
44+
45+
/// The offsett has to be lower than the percentage of the profit; the order will not be placed.
46+
case kucoinInvalidOffset(offset: Double, profitPercentage: Double)
2847

2948
/// The target price is lower than the entry price; the order will not be placed.
3049
case kucoinInvalidTargetPrice(entryPrice: String, targetPrice: String)
3150

32-
/// And error ocurred while executing the function `SwiftTrader.kucoinFuturesPlaceOrder()`.
33-
case kucoinPlaceOrder(error: Error)
34-
3551
/// And error ocurred while executing the function `SwiftTrader.kucoinFuturesOrderList(orderStatus:)`.
3652
case kucoinOrderList(error: Error)
3753

54+
/// And error ocurred while executing the function `SwiftTrader.kucoinFuturesPlaceStopLimitOrder()`.
55+
case kucoinPlaceStopLimitOrder(error: Error)
56+
57+
// MARK: Positions
58+
3859
/// And error ocurred while executing the function `SwiftTrader.kucoinFuturesPositionList()`.
3960
case kucoinPositionList(error: Error)
40-
41-
/// The response status code is something other than `200`.
42-
///
43-
/// The underlying Kucoin system error may be verified by reading the returned extra arguments, if present.
44-
case statusCodeNotOK(
45-
statusCode: Int,
46-
localizedErrorMessage: String,
47-
kucoinErrorCode: String? = nil,
48-
kucoinErrorMessage: String? = nil
49-
)
5061
}

Sources/SwiftTrader/Model/SwiftTraderOperation.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ public enum SwiftTraderOperation {
1212
case kucoinFuturesAccountOverview
1313
case kucoinFuturesCancelStopOrders
1414
case kucoinFuturesOrderList
15-
case kucoinFuturesPlaceOrder
15+
case kucoinFuturesPlaceStopLimitOrder
1616
case kucoinFuturesPositionList
1717
}

Sources/SwiftTrader/Model/SwiftTraderOrderInput.swift

+23-3
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

88
import Foundation
99

10-
/// Encapsulates all the arguments required for submiting orders to supported exchanges.
11-
public struct SwiftTraderOrderInput {
10+
/// Encapsulates all the arguments required for submiting stop limit orders to supported exchanges.
11+
public struct SwiftTraderStopLimitOrderInput {
1212

1313
// MARK: - Properties
1414

@@ -20,17 +20,36 @@ public struct SwiftTraderOrderInput {
2020
public let currentPrice: Double
2121
public let profitPercentage: Double
2222
public let offset: Double
23+
public let clean: Bool
2324

2425
// MARK: - Lifecycle
2526

27+
/// Creates a `SwiftTraderOrderInput` instance.
28+
///
29+
/// - Parameters:
30+
/// - exchange: E.g.: Kucoin, Binance
31+
/// - ticker: E.g.: BTCUSDT
32+
/// - tickerSize: E.g.: "1", "0.05", "0.00001"
33+
/// - contractSymbol: E.g.: XBTCUSDTM
34+
/// - entryPrice: E.g.: "42.856", "43567.98", "127.01".
35+
/// - currentPrice: The current price of the asset.
36+
/// - profitPercentage: The percentage of the profit at this point, e.g.: "1.5", "0.67".
37+
/// - offset: How far the **"target price"** of the stop order will be from the `currentPrice`. For example,
38+
/// suppose the `profitPercentage` is `1.0%` and the `offset` is `0.75%`. The stop order to be placed will be `0.25%`
39+
/// of the current price (`1.0%` - `0.75%`). Using the same `offset`, if the `profitPercentage` is now `2.0%`, the stop order
40+
/// will be placed at `1.25%` of the current price (`2.0%` - `0.75%`).
41+
/// - clean: When `true`, all the untriggered stop orders for the `contractSymbol` will be cancelled before placing a new one.
42+
/// Cleaning is done via `SwiftTrader.kucoinFuturesCancelStopOrders(symbol:)`. In case that fails, the execution continues
43+
/// and a new order will be placed regardless.
2644
public init(exchange: SwiftTraderExchange,
2745
ticker: String,
2846
tickerSize: String,
2947
contractSymbol: String,
3048
entryPrice: Double,
3149
currentPrice: Double,
3250
profitPercentage: Double,
33-
offset: Double) {
51+
offset: Double,
52+
clean: Bool) {
3453
self.exchange = exchange
3554
self.ticker = ticker
3655
self.tickerSize = tickerSize
@@ -39,5 +58,6 @@ public struct SwiftTraderOrderInput {
3958
self.currentPrice = currentPrice
4059
self.profitPercentage = profitPercentage
4160
self.offset = offset
61+
self.clean = clean
4262
}
4363
}

Sources/SwiftTrader/SwiftTrader+Offset.swift renamed to Sources/SwiftTrader/SwiftTrader+TrailingStop.swift

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
//
2-
// SwiftTrader+Offset.swift
2+
// SwiftTrader+TrailingStop.swift
33
//
44
//
55
// Created by Fernando Fernandes on 10.02.22.
66
//
77

88
import Foundation
99

10-
/// Creates a set of predefined parameters for interacting with target exchanges, based on a given offset.
10+
/// Creates a set of parameters for placing stop limit orders on the target exchange.
1111
///
1212
/// For example: before executing a `KucoinFuturesPlaceOrdersRequest`, this extension will create
1313
/// a `KucoinOrderParameters` instance that can be used as an argument. The business logic for creating
14-
/// such instance is based on a given `SwiftTraderOrderInput`/`offset`.
14+
/// such instance is based on a given `SwiftTraderStopLimitOrderInput`/`offset`.
1515
public extension SwiftTrader {
1616

17-
func createOrderParameters(for input: SwiftTraderOrderInput) throws -> KucoinOrderParameters {
17+
func createStopLimitOrderParameters(for input: SwiftTraderStopLimitOrderInput) throws -> KucoinOrderParameters {
1818
logger.log("Creating order parameters...")
1919

2020
// E.g: 7.47 -> 0.0747
@@ -25,7 +25,11 @@ public extension SwiftTrader {
2525
let offset: Double = (input.offset / 100)
2626
logger.log("Offset: \(offset.toDecimalString())")
2727

28-
// E.g.: (0.0747 - 0.0073) = 0.0674 (6,74%)
28+
guard offset < profitPercentage else {
29+
throw SwiftTraderError.kucoinInvalidOffset(offset: offset, profitPercentage: profitPercentage)
30+
}
31+
32+
// E.g.: (0.0747 - 0.0075) = 0.0672 (6,72%)
2933
// Use "abs" to filter out negative numbers.
3034
let targetPercentage: Double = profitPercentage - offset
3135
logger.log("Target percentage: \(targetPercentage.toDecimalString())")

Sources/SwiftTrader/SwiftTrader.swift

+14-14
Original file line numberDiff line numberDiff line change
@@ -88,23 +88,23 @@ public extension SwiftTrader {
8888

8989
// MARK: Place Orders
9090

91-
/// Places a Futures order.
91+
/// Places a Futures stop limit order.
9292
///
9393
/// https://docs.kucoin.com/futures/#place-an-order
9494
///
9595
/// - Parameter orderInput: `SwiftTraderOrderInput` instance that encapsulates
96-
/// all the arguments required for submiting the orders.
96+
/// all the arguments required for submiting the stop limit order.
9797
/// - Returns: An instance of `KucoinFuturesPlaceOrder` or `SwiftTraderError`.
98-
func kucoinFuturesPlaceOrder(_ orderInput: SwiftTraderOrderInput) async throws -> Result<KucoinFuturesPlaceOrder, SwiftTraderError> {
98+
func kucoinFuturesPlaceStopLimitOrder(_ stopLimitOrderInput: SwiftTraderStopLimitOrderInput) async throws -> Result<KucoinFuturesPlaceOrder, SwiftTraderError> {
9999

100-
#warning("TODO: parameterize cleaning up untriggered stop orders")
101-
let orderParameters = try createOrderParameters(for: orderInput)
102-
103-
do {
104-
#warning("TODO: test")
105-
try await kucoinFuturesCancelStopOrders(symbol: orderInput.contractSymbol)
106-
} catch {
107-
#warning("TODO: log")
100+
let orderParameters = try createStopLimitOrderParameters(for: stopLimitOrderInput)
101+
102+
if stopLimitOrderInput.clean {
103+
do {
104+
try await kucoinFuturesCancelStopOrders(symbol: stopLimitOrderInput.contractSymbol)
105+
} catch {
106+
logger.log("Could not cancel untriggered stop orders: \(error)")
107+
}
108108
}
109109

110110
let request = KucoinFuturesPlaceOrdersRequest(
@@ -119,7 +119,7 @@ public extension SwiftTrader {
119119
}
120120
return .success(placeOrder)
121121
case .failure(let error):
122-
let swiftTraderError = handle(networkRequestError: error, operation: .kucoinFuturesPlaceOrder)
122+
let swiftTraderError = handle(networkRequestError: error, operation: .kucoinFuturesPlaceStopLimitOrder)
123123
return .failure(swiftTraderError)
124124
}
125125
}
@@ -193,8 +193,8 @@ private extension SwiftTrader {
193193
return .kucoinFuturesCancelStopOrders(error: networkRequestError)
194194
case .kucoinFuturesOrderList:
195195
return .kucoinOrderList(error: networkRequestError)
196-
case .kucoinFuturesPlaceOrder:
197-
return .kucoinPlaceOrder(error: networkRequestError)
196+
case .kucoinFuturesPlaceStopLimitOrder:
197+
return .kucoinPlaceStopLimitOrder(error: networkRequestError)
198198
case .kucoinFuturesPositionList:
199199
return .kucoinPositionList(error: networkRequestError)
200200
}

0 commit comments

Comments
 (0)