Skip to content

Commit 1c2c94a

Browse files
author
Fernando Fernandes
committed
Add FTX list open trigger orders
1 parent 59b8257 commit 1c2c94a

11 files changed

+252
-72
lines changed

Sources/SwiftTrader/Model/Error/SwiftTraderError+Details.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ public extension SwiftTraderError {
1212

1313
static func error(for operation: SwiftTraderOperation, statusCode: Int, localizedErrorMessage: String, data: Data) -> SwiftTraderError {
1414
switch operation {
15-
case .ftxCancelAllOrders, .ftxPlaceStopLimitOrder, .ftxPositions:
15+
case .ftxCancelAllOrders,
16+
.ftxPlaceStopLimitOrder,
17+
.ftxPositions,
18+
.ftxTriggerOrdersList:
1619
guard let ftxError = try? JSONDecoder().decode(FTXError.self, from: data) else {
1720
return .ftxStatusCodeNotOK(statusCode: statusCode, localizedErrorMessage: localizedErrorMessage)
1821
}

Sources/SwiftTrader/Model/Error/SwiftTraderError.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ public enum SwiftTraderError: Error {
4949
/// And error ocurred while executing the function `SwiftTrader.ftxPositions`.
5050
case ftxPositions(error: Error)
5151

52+
/// And error ocurred while executing the function `SwiftTrader.ftxTriggerOrdersList`.
53+
case ftxTriggerOrdersList(error: Error)
54+
5255
/// The response status code is something other than `200`.
5356
case ftxStatusCodeNotOK(
5457
statusCode: Int,
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//
2+
// FTXOrder.swift
3+
//
4+
//
5+
// Created by Fernando Fernandes on 09.03.22.
6+
//
7+
8+
import Foundation
9+
10+
// Represents an order that was placed within FTX.
11+
public struct FTXOrder: Codable {
12+
13+
// MARK: - Properties
14+
15+
public let createdAt: String
16+
public let future: String
17+
public let id: Int
18+
public let market: String
19+
public let triggerPrice: Double
20+
public let side: String
21+
public let size: Double
22+
public let status: String
23+
public let type: String
24+
public let orderPrice: Double?
25+
public let error: String?
26+
public let triggeredAt: String?
27+
public let reduceOnly: Bool
28+
public let orderType: String
29+
public let retryUntilFilled: Bool
30+
31+
enum CodingKeys: String, CodingKey {
32+
case createdAt
33+
case future
34+
case id
35+
case market
36+
case triggerPrice
37+
case side
38+
case size
39+
case status
40+
case type
41+
case orderPrice
42+
case error
43+
case triggeredAt
44+
case reduceOnly
45+
case orderType
46+
case retryUntilFilled
47+
}
48+
49+
// MARK: - Lifecycle
50+
51+
public init(from decoder: Decoder) throws {
52+
let container = try decoder.container(keyedBy: CodingKeys.self)
53+
self.createdAt = try container.decode(String.self, forKey: .createdAt)
54+
self.future = try container.decode(String.self, forKey: .future)
55+
self.id = try container.decode(Int.self, forKey: .id)
56+
self.market = try container.decode(String.self, forKey: .market)
57+
self.triggerPrice = try container.decode(Double.self, forKey: .triggerPrice)
58+
self.side = try container.decode(String.self, forKey: .side)
59+
self.size = try container.decode(Double.self, forKey: .size)
60+
self.status = try container.decode(String.self, forKey: .status)
61+
self.type = try container.decode(String.self, forKey: .type)
62+
self.orderPrice = try container.decodeIfPresent(Double.self, forKey: .orderPrice)
63+
self.error = try container.decodeIfPresent(String.self, forKey: .error)
64+
self.triggeredAt = try container.decodeIfPresent(String.self, forKey: .triggeredAt)
65+
self.reduceOnly = try container.decode(Bool.self, forKey: .reduceOnly)
66+
self.orderType = try container.decode(String.self, forKey: .orderType)
67+
self.retryUntilFilled = try container.decode(Bool.self, forKey: .retryUntilFilled)
68+
}
69+
}

Sources/SwiftTrader/Model/FTX/Responses/FTXPlaceTriggerOrder.swift

Lines changed: 0 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -11,75 +11,6 @@ import Foundation
1111
///
1212
/// https://docs.ftx.com/?python#place-trigger-order
1313
public struct FTXPlaceTriggerOrder: Codable {
14-
15-
// MARK: - Properties
16-
1714
public let success: Bool
1815
public let result: FTXOrder
19-
20-
enum CodingKeys: String, CodingKey {
21-
case success
22-
case result
23-
}
24-
}
25-
26-
// Represents an order that was placed within FTX.
27-
public struct FTXOrder: Codable {
28-
29-
// MARK: - Properties
30-
31-
public let createdAt: String
32-
public let future: String
33-
public let id: Int
34-
public let market: String
35-
public let triggerPrice: Double
36-
public let side: String
37-
public let size: Double
38-
public let status: String
39-
public let type: String
40-
public let orderPrice: Double?
41-
public let error: String?
42-
public let triggeredAt: String?
43-
public let reduceOnly: Bool
44-
public let orderType: String
45-
public let retryUntilFilled: Bool
46-
47-
enum CodingKeys: String, CodingKey {
48-
case createdAt
49-
case future
50-
case id
51-
case market
52-
case triggerPrice
53-
case side
54-
case size
55-
case status
56-
case type
57-
case orderPrice
58-
case error
59-
case triggeredAt
60-
case reduceOnly
61-
case orderType
62-
case retryUntilFilled
63-
}
64-
65-
// MARK: - Lifecycle
66-
67-
public init(from decoder: Decoder) throws {
68-
let container = try decoder.container(keyedBy: CodingKeys.self)
69-
self.createdAt = try container.decode(String.self, forKey: .createdAt)
70-
self.future = try container.decode(String.self, forKey: .future)
71-
self.id = try container.decode(Int.self, forKey: .id)
72-
self.market = try container.decode(String.self, forKey: .market)
73-
self.triggerPrice = try container.decode(Double.self, forKey: .triggerPrice)
74-
self.side = try container.decode(String.self, forKey: .side)
75-
self.size = try container.decode(Double.self, forKey: .size)
76-
self.status = try container.decode(String.self, forKey: .status)
77-
self.type = try container.decode(String.self, forKey: .type)
78-
self.orderPrice = try container.decodeIfPresent(Double.self, forKey: .orderPrice)
79-
self.error = try container.decodeIfPresent(String.self, forKey: .error)
80-
self.triggeredAt = try container.decodeIfPresent(String.self, forKey: .triggeredAt)
81-
self.reduceOnly = try container.decode(Bool.self, forKey: .reduceOnly)
82-
self.orderType = try container.decode(String.self, forKey: .orderType)
83-
self.retryUntilFilled = try container.decode(Bool.self, forKey: .retryUntilFilled)
84-
}
8516
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//
2+
// FTXTriggerOrders.swift
3+
//
4+
//
5+
// Created by Fernando Fernandes on 09.03.22.
6+
//
7+
8+
import Foundation
9+
10+
/// FTX "Place Trigger Order" REST API response.
11+
///
12+
/// https://docs.ftx.com/?python#get-open-trigger-orders
13+
public struct FTXTriggerOrders: Codable {
14+
public let success: Bool
15+
public let result: [FTXOrder]
16+
}

Sources/SwiftTrader/Model/SwiftTraderOperation.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public enum SwiftTraderOperation {
1515
case ftxCancelAllOrders
1616
case ftxPlaceStopLimitOrder
1717
case ftxPositions
18+
case ftxTriggerOrdersList
1819

1920
// MARK: - Kucoin
2021

Sources/SwiftTrader/Network/FTX/FTXAPI.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,8 @@ public struct FTXAPI {
2525
static let orders = "/api/orders"
2626
static let positions = "/api/positions"
2727
}
28+
29+
public struct QueryParam {
30+
public static let market = "market"
31+
}
2832
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//
2+
// FTXListTriggerOrdersRequest.swift
3+
//
4+
//
5+
// Created by Fernando Fernandes on 09.03.22.
6+
//
7+
8+
import Foundation
9+
#if canImport(FoundationNetworking)
10+
import FoundationNetworking
11+
#endif
12+
import Logging
13+
14+
/// A **request** for listing all open trigger orders of a given (contract) symbol.
15+
///
16+
/// https://docs.ftx.com/?python#get-open-trigger-orders
17+
public struct FTXListTriggerOrdersRequest: NetworkRequest {
18+
19+
// MARK: - Properties
20+
21+
public typealias DecodableModel = FTXTriggerOrders
22+
23+
public var logger: Logger {
24+
NetworkRequestLogger().default
25+
}
26+
27+
public var session: URLSession
28+
29+
public var request: URLRequest {
30+
get throws {
31+
let listTriggerOrdersResource = FTXListTriggerOrdersResource(market: market)
32+
var urlRequest = URLRequest(url: try listTriggerOrdersResource.url)
33+
urlRequest.httpMethod = HTTPMethod.GET.rawValue
34+
try FTXAPI.setRequestHeaderFields(request: &urlRequest, ftxAuth: ftxAuth)
35+
return urlRequest
36+
}
37+
}
38+
39+
public var settings: NetworkRequestSettings
40+
41+
// MARK: Private
42+
43+
private let market: String
44+
45+
private let ftxAuth: FTXAuth
46+
47+
// MARK: - Lifecycle
48+
49+
/// Creates a new `FTXListTriggerOrdersRequest` instance.
50+
///
51+
/// - Parameters:
52+
/// - market: `String`, Restrict to cancelling orders only on this market. E.g.: "PAXG-PERP".
53+
/// - ftxAuth: FTX authentication data.
54+
/// - session: `URLSession`, default is `.shared`.
55+
/// - settings: `NetworkRequestSettings`.
56+
public init(market: String,
57+
ftxAuth: FTXAuth,
58+
session: URLSession = .shared,
59+
settings: NetworkRequestSettings) {
60+
self.market = market
61+
self.ftxAuth = ftxAuth
62+
self.session = session
63+
self.settings = settings
64+
}
65+
}
66+
67+
// MARK: - Network Request Protocol
68+
69+
public extension FTXListTriggerOrdersRequest {
70+
71+
func decode(_ data: Data) throws -> DecodableModel {
72+
try JSONDecoder().decode(FTXTriggerOrders.self, from: data)
73+
}
74+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//
2+
// FTXListTriggerOrdersResource.swift
3+
//
4+
//
5+
// Created by Fernando Fernandes on 09.03.22.
6+
//
7+
8+
import Foundation
9+
10+
/// The **resource** for requesting the list of all open trigger orders of a given (contract) symbol.
11+
///
12+
/// https://docs.ftx.com/?python#get-open-trigger-orders
13+
public struct FTXListTriggerOrdersResource: NetworkResource {
14+
15+
// MARK: - Properties
16+
17+
public var url: URL {
18+
get throws {
19+
let baseURLString = FTXAPI.BaseURL.production
20+
guard var urlComponents = URLComponents(string: baseURLString) else {
21+
throw NetworkRequestError.invalidURLString(urlString: baseURLString)
22+
}
23+
urlComponents.path = FTXAPI.Path.conditionalOrders
24+
let queryItems = [
25+
URLQueryItem(name: FTXAPI.QueryParam.market, value: market)
26+
]
27+
urlComponents.queryItems = queryItems
28+
guard let url = urlComponents.url else {
29+
throw NetworkRequestError.invalidURLString(urlString: baseURLString)
30+
}
31+
return url
32+
}
33+
}
34+
35+
// MARK: Private
36+
37+
private let market: String
38+
39+
// MARK: - Lifecycle
40+
41+
/// Creates a new `FTXListTriggerOrdersResource` instance.
42+
///
43+
/// - Parameter market: `String`, Restrict to cancelling orders only on this market.
44+
/// E.g.: "PAXG-PERP".
45+
init(market: String) {
46+
self.market = market
47+
}
48+
}

Sources/SwiftTrader/SwiftTrader+Error.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@ public extension SwiftTrader {
1616
return SwiftTraderError.error(for: operation, statusCode: statusCode, localizedErrorMessage: errorMessage, data: data)
1717
default:
1818
switch operation {
19+
case .ftxCancelAllOrders:
20+
return .ftxCancelAllOrders(error: networkRequestError)
1921
case .ftxPlaceStopLimitOrder:
2022
return .ftxPlaceStopLimitOrder(error: networkRequestError)
2123
case .ftxPositions:
2224
return .ftxPositions(error: networkRequestError)
23-
case .ftxCancelAllOrders:
24-
return .ftxCancelAllOrders(error: networkRequestError)
25+
case .ftxTriggerOrdersList:
26+
return .ftxTriggerOrdersList(error: networkRequestError)
2527
case .kucoinFuturesAccountOverview:
2628
return .kucoinFuturesAccountOverview(error: networkRequestError)
2729
case .kucoinFuturesCancelStopOrders:

0 commit comments

Comments
 (0)