Skip to content

Commit c2aa572

Browse files
author
Fernando Fernandes
committed
Add call to get futures position list
1 parent 92bbeab commit c2aa572

File tree

8 files changed

+256
-21
lines changed

8 files changed

+256
-21
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//
2+
// KucoinFuturesPositionList.swift
3+
//
4+
//
5+
// Created by Fernando Fernandes on 06.02.22.
6+
//
7+
8+
import Foundation
9+
10+
/// Kucoin "Get Position List" REST API response.
11+
///
12+
/// https://docs.kucoin.com/futures/#get-position-list
13+
public struct KucoinFuturesPositionList: Codable {
14+
public let code: String
15+
public let data: [KucoinFuturesPosition]
16+
}
17+
18+
public struct KucoinFuturesPosition: Codable {
19+
20+
// MARK: - Properties
21+
22+
let id: String
23+
24+
/// E.g.: XBTUSDTM
25+
let symbol: String
26+
let autoDeposit: Bool
27+
let realLeverage: Double
28+
let crossMode: Bool
29+
let delevPercentage: Double
30+
31+
/// Opening date in milliseconds.
32+
let openingTimestamp: Int64
33+
/// Opening date as string (E.g.: "Saturday, 5. February 2022 at 22:32:16").
34+
let openingTimestampString: String
35+
36+
/// Current date in milliseconds.
37+
let currentTimestamp: Int64
38+
/// Current date as string (E.g.: "Saturday, 5. February 2022 at 22:32:16").
39+
let currentTimestampString: String
40+
41+
let posInit: Double
42+
let currentQty: Int
43+
let isOpen: Bool
44+
let realisedPnl: Double
45+
let unrealisedPnl: Double
46+
let avgEntryPrice: Double
47+
let liquidationPrice: Double
48+
49+
enum CodingKeys: String, CodingKey {
50+
case id
51+
case symbol
52+
case autoDeposit
53+
case realLeverage
54+
case crossMode
55+
case delevPercentage
56+
case openingTimestamp
57+
case openingTimestampString
58+
case currentTimestamp
59+
case currentTimestampString
60+
case posInit
61+
case currentQty
62+
case isOpen
63+
case realisedPnl
64+
case unrealisedPnl
65+
case avgEntryPrice
66+
case liquidationPrice
67+
}
68+
69+
// MARK: - Lifecycle
70+
71+
public init(from decoder: Decoder) throws {
72+
let container = try decoder.container(keyedBy: CodingKeys.self)
73+
self.id = try container.decode(String.self, forKey: .id)
74+
self.symbol = try container.decode(String.self, forKey: .symbol)
75+
self.autoDeposit = try container.decode(Bool.self, forKey: .autoDeposit)
76+
self.realLeverage = try container.decode(Double.self, forKey: .realLeverage)
77+
self.crossMode = try container.decode(Bool.self, forKey: .crossMode)
78+
self.delevPercentage = try container.decode(Double.self, forKey: .delevPercentage)
79+
80+
self.openingTimestamp = try container.decode(Int64.self, forKey: .openingTimestamp)
81+
self.openingTimestampString = Date(milliseconds: self.openingTimestamp).toString()
82+
83+
self.currentTimestamp = try container.decode(Int64.self, forKey: .currentTimestamp)
84+
self.currentTimestampString = Date(milliseconds: self.currentTimestamp).toString()
85+
86+
self.posInit = try container.decode(Double.self, forKey: .posInit)
87+
self.currentQty = try container.decode(Int.self, forKey: .currentQty)
88+
self.isOpen = try container.decode(Bool.self, forKey: .isOpen)
89+
self.realisedPnl = try container.decode(Double.self, forKey: .realisedPnl)
90+
self.unrealisedPnl = try container.decode(Double.self, forKey: .unrealisedPnl)
91+
self.avgEntryPrice = try container.decode(Double.self, forKey: .avgEntryPrice)
92+
self.liquidationPrice = try container.decode(Double.self, forKey: .liquidationPrice)
93+
}
94+
}

Sources/SwiftTrader/Model/Kucoin/Order/KucoinFuturesOrderList.swift

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,16 @@ public struct KucoinFuturesOrder: Codable {
6666
/// Mark of the canceled orders.
6767
let cancelExist: Bool
6868
let status: KucoinOrderStatus
69-
let createdAt: String
7069

71-
/// Last update time.
72-
let updatedAt: String
70+
/// Creation date in milliseconds.
71+
let createdAt: Int64
72+
/// Creation date as string (E.g.: "Saturday, 5. February 2022 at 22:32:16").
73+
let createdAtString: String
74+
75+
/// Last update time in milliseconds.
76+
let updatedAt: Int64
77+
/// Last update time as string (E.g.: "Saturday, 5. February 2022 at 22:32:16")
78+
let updatedAtString: String
7379

7480
enum CodingKeys: String, CodingKey {
7581
case id
@@ -90,9 +96,11 @@ public struct KucoinFuturesOrder: Codable {
9096
case clientOid
9197
case isActive
9298
case cancelExist
93-
case createdAt
9499
case status
100+
case createdAt
101+
case createdAtString
95102
case updatedAt
103+
case updatedAtString
96104
}
97105

98106
// MARK: - Lifecycle
@@ -135,10 +143,10 @@ public struct KucoinFuturesOrder: Codable {
135143
self.cancelExist = try container.decode(Bool.self, forKey: .cancelExist)
136144
self.status = try container.decode(KucoinOrderStatus.self, forKey: .status)
137145

138-
let createdAtMilliseconds = try container.decode(Int64.self, forKey: .createdAt)
139-
self.createdAt = Date(milliseconds: createdAtMilliseconds).toString()
146+
self.createdAt = try container.decode(Int64.self, forKey: .createdAt)
147+
self.createdAtString = Date(milliseconds: self.createdAt).toString()
140148

141-
let updatedAtMilliseconds = try container.decode(Int64.self, forKey: .updatedAt)
142-
self.updatedAt = Date(milliseconds: updatedAtMilliseconds).toString()
149+
self.updatedAt = try container.decode(Int64.self, forKey: .updatedAt)
150+
self.updatedAtString = Date(milliseconds: self.updatedAt).toString()
143151
}
144152
}

Sources/SwiftTrader/Network/Kucoin/KucoinAPI.swift

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@ public struct KucoinAPI {
1313
public struct Futures {
1414

1515
public struct Path {
16-
static let accountOverview = "/api/v1/account-overview"
17-
static let orderList = "/api/v1/orders"
16+
static let accountOverview = "/api/v1/account-overview"
17+
static let orderList = "/api/v1/orders"
18+
static let positionList = "/api/v1/positions"
1819
}
1920

2021
public struct URL {
21-
static let base = "https://api-futures.kucoin.com"
22-
static let sandbox = "https://api-sandbox-futures.kucoin.com"
22+
static let base = "https://api-futures.kucoin.com"
23+
static let sandbox = "https://api-sandbox-futures.kucoin.com"
2324
}
2425
}
2526

@@ -31,7 +32,7 @@ public struct KucoinAPI {
3132
}
3233

3334
public struct QueryParam {
34-
static let currency = "currency"
35-
static let orderStatus = "status"
35+
static let currency = "currency"
36+
static let orderStatus = "status"
3637
}
3738
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//
2+
// KucoinFuturesPositionListRequest.swift
3+
//
4+
//
5+
// Created by Fernando Fernandes on 29.01.22.
6+
//
7+
8+
import Foundation
9+
#if canImport(FoundationNetworking)
10+
import FoundationNetworking
11+
#endif
12+
import Logging
13+
14+
/// A **request** for the list of positions.
15+
///
16+
/// https://docs.kucoin.com/futures/#get-position-list
17+
public struct KucoinFuturesPositionListRequest: NetworkRequest {
18+
19+
// MARK: - Properties
20+
21+
public typealias DecodableModel = KucoinFuturesPositionList
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 futuresPositionListResource = KucoinFuturesPositionListResource()
32+
var urlRequest = URLRequest(url: try futuresPositionListResource.url)
33+
urlRequest.httpMethod = HTTPMethod.GET.rawValue
34+
try KucoinAPI.setRequestHeaderFields(request: &urlRequest, kucoinAuth: kucoinAuth)
35+
return urlRequest
36+
}
37+
}
38+
39+
public var settings: NetworkRequestSettings
40+
41+
// MARK: Private
42+
43+
private let kucoinAuth: KucoinAuth
44+
45+
// MARK: - Lifecycle
46+
47+
/// Creates a new `KucoinFuturesAccountOverviewRequest` instance.
48+
///
49+
/// - Parameters:
50+
/// - session: `URLSession`, default is `.shared`.
51+
/// - kucoinAuth: Kucoin authentication data.
52+
/// - settings: `NetworkRequestSettings`.
53+
public init(session: URLSession = .shared,
54+
kucoinAuth: KucoinAuth,
55+
settings: NetworkRequestSettings) {
56+
self.session = session
57+
self.kucoinAuth = kucoinAuth
58+
self.settings = settings
59+
}
60+
}
61+
62+
// MARK: - Network Request Protocol
63+
64+
public extension KucoinFuturesPositionListRequest {
65+
66+
func decode(_ data: Data) throws -> DecodableModel {
67+
try JSONDecoder().decode(KucoinFuturesPositionList.self, from: data)
68+
}
69+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//
2+
// KucoinFuturesPositionListResource.swift
3+
//
4+
//
5+
// Created by Fernando Fernandes on 04.02.22.
6+
//
7+
8+
import Foundation
9+
10+
/// The **resource** for requesting the list of current positions.
11+
///
12+
/// https://docs.kucoin.com/futures/#get-position-list
13+
public struct KucoinFuturesPositionListResource: NetworkResource {
14+
15+
// MARK: - Properties
16+
17+
public var url: URL {
18+
get throws {
19+
let baseURLString = KucoinAPI.Futures.URL.base
20+
guard var urlComponents = URLComponents(string: baseURLString) else {
21+
throw NetworkRequestError.invalidURLString(urlString: baseURLString)
22+
}
23+
urlComponents.path = KucoinAPI.Futures.Path.positionList
24+
guard let url = urlComponents.url else {
25+
throw NetworkRequestError.invalidURLString(urlString: baseURLString)
26+
}
27+
return url
28+
}
29+
}
30+
}

Sources/SwiftTrader/SwiftTrader.swift

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,20 +69,33 @@ public extension SwiftTrader {
6969
return .failure(swiftTraderError)
7070
}
7171
}
72+
73+
// MARK: Positions
74+
75+
func kucoinFuturesPositionList() async throws -> Result<KucoinFuturesPositionList, SwiftTraderError> {
76+
let request = KucoinFuturesPositionListRequest(
77+
kucoinAuth: kucoinAuth,
78+
settings: settings.networkRequestSettings
79+
)
80+
switch await request.execute() {
81+
case .success(let model):
82+
guard let positionList = model as? KucoinFuturesPositionList else {
83+
return .failure(.unexpectedResponse(modelString: "\(model)"))
84+
}
85+
return .success(positionList)
86+
case .failure(let error):
87+
let swiftTraderError = handle(networkRequestError: error, operation: .kucoinFuturesPositionList)
88+
return .failure(swiftTraderError)
89+
}
90+
}
7291
}
7392

7493
// MARK: - Private
7594

76-
/// The currently running SwiftTrader operation.
77-
private enum Operation {
78-
case kucoinFuturesAccountOverview
79-
case kucoinFuturesOrderList
80-
}
81-
8295
private extension SwiftTrader {
8396

8497
/// Translates a `NetworkRequestError` to a `SwiftTraderError`.
85-
func handle(networkRequestError: NetworkRequestError, operation: Operation) -> SwiftTraderError {
98+
func handle(networkRequestError: NetworkRequestError, operation: SwiftTraderOperation) -> SwiftTraderError {
8699
switch networkRequestError {
87100
case .statusCodeNotOK(let statusCode, let errorMessage, let data):
88101
let error = SwiftTraderError.error(for: statusCode, localizedErrorMessage: errorMessage, data: data)
@@ -93,6 +106,8 @@ private extension SwiftTrader {
93106
return .kucoinFuturesAccountOverviewError(error: networkRequestError)
94107
case .kucoinFuturesOrderList:
95108
return .kucoinOrderListError(error: networkRequestError)
109+
case .kucoinFuturesPositionList:
110+
return .kucoinPositionListError(error: networkRequestError)
96111
}
97112
}
98113
}

Sources/SwiftTrader/SwiftTraderError.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ public enum SwiftTraderError: Error {
2323
/// And error ocurred while executing the function `SwiftTrader.kucoinFuturesOrderList(orderStatus:)`.
2424
case kucoinOrderListError(error: Error)
2525

26+
/// And error ocurred while executing the function `SwiftTrader.kucoinFuturesPositionList()`.
27+
case kucoinPositionListError(error: Error)
28+
2629
/// The response status code is something other than `200`.
2730
///
2831
/// The underlying Kucoin system error may be verified by reading the returned extra arguments, if present.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//
2+
// SwiftTraderOperation.swift
3+
//
4+
//
5+
// Created by Fernando Fernandes on 06.02.22.
6+
//
7+
8+
import Foundation
9+
10+
/// The currently running `SwiftTrader` operation.
11+
public enum SwiftTraderOperation {
12+
case kucoinFuturesAccountOverview
13+
case kucoinFuturesOrderList
14+
case kucoinFuturesPositionList
15+
}

0 commit comments

Comments
 (0)