@@ -15,22 +15,74 @@ import Foundation
1515public extension SwiftTrader {
1616
1717 func createOrderParameters( for input: SwiftTraderOrderInput ) -> KucoinOrderParameters {
18- let targetPercentage : Double = ( input. profitPercentage / 100 ) - ( input. offset / 100 )
18+ logger. log ( " Creating order parameters... " )
19+
20+ // E.g: 7.47 -> 0.0747
21+ let profitPercentage : Double = ( input. profitPercentage / 100 )
22+ logger. log ( " Profit percentage: \( profitPercentage. toDecimalString ( ) ) " )
23+
24+ // Instead of creating an order with a fixed target percentage (say 0.025), add some fat to it (e.g.: 0.027)
25+ let offsetMargin : Double = 0.02
26+ logger. log ( " Offset margin: \( offsetMargin. toDecimalString ( ) ) " )
27+
28+ // E.g.: (0.75 - 0.02) / 100 = 0.0073, which translates to 0.0027 (0,27%)
29+ let offset : Double = ( input. offset - offsetMargin) / 100
30+ logger. log ( " Offset: \( offset. toDecimalString ( ) ) " )
31+
32+ // E.g.: (0.0747 - 0.0073) = 0.0674 (6,74%)
33+ let targetPercentage : Double = profitPercentage - offset
34+ logger. log ( " Target percentage: \( targetPercentage. toDecimalString ( ) ) " )
35+
36+ // E.g.: 42000.69 * 0.0674 = 2830.846506
1937 let priceIncrement : Double = input. entryPrice * targetPercentage
38+ logger. log ( " Price increment: \( priceIncrement. toDecimalString ( ) ) " )
39+
40+ // E.g.: 42000.9 + 2830.846506 = 44831.536506
41+ let targetPrice : Double = input. entryPrice + priceIncrement
42+ logger. log ( " Entry price: \( input. entryPrice. toDecimalString ( ) ) " )
43+ logger. log ( " Target price: \( targetPrice. toDecimalString ( ) ) " )
44+
45+ // Now in order to avoid a huge difference between the entry price and the target price in terms of size,
46+ // "normalize" them based on the entry price by first counting its characters.
47+ let entryPriceCount = input. entryPrice. toDecimalString ( ) . count
48+ logger. log ( " Entry price count: \( entryPriceCount) " )
49+
50+ // Count the target price characters too.
51+ let targetPriceCount = targetPrice. toDecimalString ( ) . count
52+ logger. log ( " Target price count: \( targetPriceCount) " )
53+
54+ // E.g.: 12 - 8 (44831.536506 - 42000.69)
55+ // "44831.536506" becomes "44831.53".
56+ let charactersToBeRemoved = abs ( targetPriceCount - entryPriceCount)
57+ var targetPriceString = " \( targetPrice. toDecimalString ( ) ) " . dropLast ( charactersToBeRemoved)
58+ logger. log ( " Target price normalize: \( targetPriceString) " )
59+
60+ // Finally, avoid the following Kucoin error with minimal effort: "The parameter shall be a multiple of ..."
61+ // First, just try replacing the last character by "1". E.g.: "0.00002347" becomes "0.00002341"
62+ if targetPriceString. components ( separatedBy: " . " ) . count > 1 {
63+ targetPriceString = targetPriceString. dropLast ( ) + " 1 "
64+ } else {
65+ // Handles whole numbers: "3735" becomes "3735.1" (instead of "3731").
66+ targetPriceString += " .1 "
67+ }
68+ logger. log ( " Target price string: \( targetPriceString) " )
2069
21- #warning("TODO: round up?")
22- // Why Int? From a Kucoin response: "The parameter shall be a multiple of 1."
23- let targetPrice = Int ( input. entryPrice + priceIncrement)
24- let targetPriceString = String ( targetPrice)
70+ // E.g.: "44831.53" becomes "44831".
71+ // Workaround to not call "https://docs.kucoin.com/futures/#get-open-contract-list" (for now).
72+ // "The price specified must be a multiple number of the contract tickSize, otherwise the system will report an
73+ // error when you place the order. The tick size is the smallest price increment in which the prices are quoted.
74+ if let priceDouble = Double ( targetPriceString) , priceDouble > 10 {
75+ targetPriceString = " \( priceDouble. rounded ( . down) . toDecimalString ( ) ) "
76+ }
2577
2678 return KucoinOrderParameters (
2779 symbol: input. contractSymbol,
2880 side: . sell,
2981 type: . limit,
3082 stop: . down,
3183 stopPriceType: . TP,
32- stopPrice: targetPriceString,
33- price: targetPriceString,
84+ stopPrice: " \( targetPriceString) " ,
85+ price: " \( targetPriceString) " ,
3486 reduceOnly: true ,
3587 closeOrder: true
3688 )
0 commit comments