From b6e6299ad04e89ec64621ae575ba6d8afd5d78fa Mon Sep 17 00:00:00 2001 From: Terrick Mansur Date: Thu, 25 Jan 2018 20:09:04 +0100 Subject: [PATCH 1/4] Adds: ETC, BCH, DOGE, XMR, ZEC, DASH to Currency enum. --- Common/Currency.swift | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Common/Currency.swift b/Common/Currency.swift index 880e11b..532eb04 100644 --- a/Common/Currency.swift +++ b/Common/Currency.swift @@ -60,7 +60,6 @@ public extension Currency { static let INR = Currency(name: "Indian rupee", code: "INR") static let BRL = Currency(name: "Brazilian real", code: "BRL") static let ZAR = Currency(name: "South African rand", code: "ZAR") - static let Bitcoin = Currency(name: "Bitcoin", code: "BTC") static let Ethereum = Currency(name: "Ethereum", code: "ETH") static let Litecoin = Currency(name: "Litecoin", code: "LTC") @@ -68,6 +67,13 @@ public extension Currency { static let Cardano = Currency(name: "Cardano", code: "ADA") static let NEM = Currency(name: "NEM", code: "XEM") static let USDT = Currency(name: "Tether USD", code: "USDT") + static let ETC = Currency(name: "Ethereum Classic", code: "ETC") + static let BCH = Currency(name: "Bitcoin Cash", code: "BCH") + static let DOGE = Currency(name: "Dogecoin", code: "DOGE") + static let XMR = Currency(name: "Monero", code: "XMR") + static let ZEC = Currency(name: "Zcash", code: "ZEC") + static let DASH = Currency(name: "Dash", code: "DASH") + static let currencies: [Currency] = [ USD, EUR, JPY, GBP, AUD, CAD, CHF, CNY, SEK, NZD, MXN, SGD, HKD, NOK, KRW, TRY, RUB, INR, BRL, ZAR, Bitcoin, @@ -76,6 +82,12 @@ public extension Currency { Litecoin, Cardano, NEM, - USDT - ] + USDT, + ETC, + BCH, + DOGE, + XMR, + ZEC, + DASH + ] } From 35faa9357c7f962fcff6f4585341c8d65e8a3af6 Mon Sep 17 00:00:00 2001 From: Terrick Mansur Date: Fri, 26 Jan 2018 00:07:07 +0100 Subject: [PATCH 2/4] Implements getOpenOrders for Cryptopia. --- Binance/Binance.swift | 4 +-- BitGrail/BitGrail.swift | 2 +- Bitfinex/Bitfinex.swift | 4 +-- CoinExchange/CoinExchange.swift | 4 +-- CoinMarketCap/CoinMarketCap.swift | 2 +- Common/Balance.swift | 24 +++++++++++++++ Common/ExchangeDataStore.swift | 5 ++-- Cryptopia/Cryptopia.swift | 49 ++++++++++++++++++++++++++++--- GDAX/GDAX.swift | 4 +-- Gemini/Gemini.swift | 4 +-- Koinex/Koinex.swift | 2 +- Kraken/Kraken.swift | 4 +-- Poloniex/Poloniex.swift | 4 +-- 13 files changed, 89 insertions(+), 23 deletions(-) diff --git a/Binance/Binance.swift b/Binance/Binance.swift index 0b96445..47ba97d 100644 --- a/Binance/Binance.swift +++ b/Binance/Binance.swift @@ -35,7 +35,7 @@ public struct Binance { balances = [] } } - + public class Balance: Cryptex.Balance { public var locked: NSDecimalNumber @@ -51,7 +51,7 @@ public struct Binance { } } - public class Store: ExchangeDataStore { + public class Store: ExchangeDataStore { public static var shared = Store() diff --git a/BitGrail/BitGrail.swift b/BitGrail/BitGrail.swift index fa8a3bb..5c79b5e 100644 --- a/BitGrail/BitGrail.swift +++ b/BitGrail/BitGrail.swift @@ -72,7 +72,7 @@ public struct BitGrail { case getBalance } - public class Store: ExchangeDataStore { + public class Store: ExchangeDataStore { public static var shared = Store() override private init() { diff --git a/Bitfinex/Bitfinex.swift b/Bitfinex/Bitfinex.swift index 258b594..75b1630 100644 --- a/Bitfinex/Bitfinex.swift +++ b/Bitfinex/Bitfinex.swift @@ -47,8 +47,8 @@ public struct Bitfinex { super.init(currency: currencyStore.forCode(json["currency"] ?? ""), quantity: available) } } - - public class Store: ExchangeDataStore { + + public class Store: ExchangeDataStore { public static var shared = Store() override private init() { diff --git a/CoinExchange/CoinExchange.swift b/CoinExchange/CoinExchange.swift index 4d832af..b4e5d0b 100644 --- a/CoinExchange/CoinExchange.swift +++ b/CoinExchange/CoinExchange.swift @@ -107,8 +107,8 @@ public struct CoinExchange { case getmarketsummaries case getBalance } - - public class Store: ExchangeDataStore { + + public class Store: ExchangeDataStore { public static var shared = Store() override private init() { diff --git a/CoinMarketCap/CoinMarketCap.swift b/CoinMarketCap/CoinMarketCap.swift index 27767e2..cb3215b 100644 --- a/CoinMarketCap/CoinMarketCap.swift +++ b/CoinMarketCap/CoinMarketCap.swift @@ -85,7 +85,7 @@ public struct CoinMarketCap { case getGlobal } - public class Store: ExchangeDataStore { + public class Store: ExchangeDataStore { public static var shared = Store() override private init() { diff --git a/Common/Balance.swift b/Common/Balance.swift index 769fef2..f539554 100644 --- a/Common/Balance.swift +++ b/Common/Balance.swift @@ -7,6 +7,30 @@ import Foundation +public enum OrderType: String { + case Buy = "Buy" + case Sell = "Sell" +} + +public protocol OrderProtocol { + var type: OrderType? { get } + var rate: NSDecimalNumber? { get } +} + +open class Order: OrderProtocol { + + public var id: String? + public var type: OrderType? + public var rate: NSDecimalNumber? + public var amount: NSDecimalNumber? + public var remaining: NSDecimalNumber? + public var total: NSDecimalNumber? + public var market: CurrencyPair? + + init(json: [String: Any]) { + } +} + public protocol BalanceType { var currency: Currency { get } var quantity: NSDecimalNumber { get } diff --git a/Common/ExchangeDataStore.swift b/Common/ExchangeDataStore.swift index 7f1c638..60a9a28 100644 --- a/Common/ExchangeDataStore.swift +++ b/Common/ExchangeDataStore.swift @@ -7,7 +7,7 @@ import Foundation -public class ExchangeDataStore { +public class ExchangeDataStore { public var name = "ExchangeDataStore" public var accountingCurrency: Currency = .USD @@ -18,7 +18,8 @@ public class ExchangeDataStore { public var tickerByName: [T] = [] public var balances: [U] = [] - + public var openOrders: [O] = [] + public var tickersDictionary: [String: T] = [:] { didSet { let tickers = tickersDictionary.values.flatMap{$0} diff --git a/Cryptopia/Cryptopia.swift b/Cryptopia/Cryptopia.swift index dc1de0a..c9b3239 100644 --- a/Cryptopia/Cryptopia.swift +++ b/Cryptopia/Cryptopia.swift @@ -102,6 +102,24 @@ public struct Cryptopia { } } + public class CryptopiaOrder: Order { + + override init(json: [String: Any]) { + super.init(json: json) + self.rate = NSDecimalNumber(json["Rate"]) + self.amount = NSDecimalNumber(json["Amount"]) + self.remaining = NSDecimalNumber(json["Remaining"]) + self.total = NSDecimalNumber(json["Total"]) + if let market = json["Market"] as? String { + let split = market.components(separatedBy: "/") + if split.count == 2 { + self.market = CurrencyPair(quantity: Currency(code: split[1]), price: Currency(code: split[0])) + } + } + + self.type = OrderType(rawValue: (json["Type"] as? String) ?? "") + } + } public class CryptopiaCurrency: Currency { public var id: Int public var symbol: String @@ -154,12 +172,13 @@ public struct Cryptopia { public enum API { case getMarkets case getBalance + case getOpenOrders // case getCurrencies case getTradePairs } - public class Store: ExchangeDataStore { + public class Store: ExchangeDataStore { public static var shared = Store() override private init() { @@ -170,6 +189,8 @@ public struct Cryptopia { public var tickersResponse: HTTPURLResponse? = nil public var balanceResponse: HTTPURLResponse? = nil + public var openOrdersResponse: HTTPURLResponse? = nil + public var currenciesResponse: (response: HTTPURLResponse?, currencies: [CryptopiaCurrency]) = (nil, []) } @@ -232,6 +253,22 @@ public struct Cryptopia { } } + public func getOpenOrders(completion: @escaping (ResponseType) -> Void) { + let apiType = Cryptopia.API.getOpenOrders + + if apiType.checkInterval(response: store.openOrdersResponse) { + completion(.cached) + } else { + cryptopiaDataTaskFor(api: apiType) { (json, response, error) in + guard let json = json as? [[String: Any]] else { return } + let openOrders = json.map { CryptopiaOrder(json: $0) } + self.store.openOrders = openOrders + self.store.openOrdersResponse = response + completion(.fetched) + }.resume() + } + } + public func getBalances(completion: @escaping (ResponseType) -> Void) { let apiType = Cryptopia.API.getBalance @@ -242,14 +279,12 @@ public struct Cryptopia { } else { cryptopiaDataTaskFor(api: apiType) { (json, response, error) in - guard let json = json as? [[String: Any]] else { return } let balances = json.map { Balance(json: $0, currencyStore: self.activeCurrencyStore()) }.filter { $0.available != .zero } self.store.balances = balances self.store.balanceResponse = response completion(.fetched) - - }.resume() + }.resume() } } @@ -322,6 +357,7 @@ extension Cryptopia.API: APIType { case .getTradePairs: return "/GetTradePairs" case .getMarkets: return "/GetMarkets" case .getBalance: return "/GetBalance" + case .getOpenOrders: return "/GetOpenOrders" } } @@ -331,6 +367,7 @@ extension Cryptopia.API: APIType { case .getTradePairs: return .GET case .getMarkets: return .GET case .getBalance: return .POST + case .getOpenOrders: return .POST } } @@ -340,6 +377,7 @@ extension Cryptopia.API: APIType { case .getTradePairs: return false case .getMarkets: return false case .getBalance: return true + case .getOpenOrders: return true } } @@ -349,6 +387,7 @@ extension Cryptopia.API: APIType { case .getTradePairs: return .url case .getMarkets: return .url case .getBalance: return .url + case .getOpenOrders: return .url } } @@ -358,6 +397,7 @@ extension Cryptopia.API: APIType { case .getTradePairs: return [:] case .getMarkets: return [:] case .getBalance: return [:] + case .getOpenOrders: return [:] } } @@ -367,6 +407,7 @@ extension Cryptopia.API: APIType { case .getTradePairs: return .aMonth case .getMarkets: return .aMinute case .getBalance: return .aMinute + case .getOpenOrders: return .aMinute } } } diff --git a/GDAX/GDAX.swift b/GDAX/GDAX.swift index 69d1d9a..62d4821 100644 --- a/GDAX/GDAX.swift +++ b/GDAX/GDAX.swift @@ -86,8 +86,8 @@ public struct GDAX { super.init(currency: currencyStore.forCode( json["currency"] as? String ?? "" ), quantity: NSDecimalNumber(json["balance"])) } } - - public class Store: ExchangeDataStore { + + public class Store: ExchangeDataStore { public static var shared = Store() override private init() { diff --git a/Gemini/Gemini.swift b/Gemini/Gemini.swift index 07b39be..1aefbd1 100644 --- a/Gemini/Gemini.swift +++ b/Gemini/Gemini.swift @@ -123,8 +123,8 @@ public struct Gemini { isAuctionFill = json["is_auction_fill"] as! Bool } } - - public class Store: ExchangeDataStore { + + public class Store: ExchangeDataStore { public static var shared = Store() override private init() { diff --git a/Koinex/Koinex.swift b/Koinex/Koinex.swift index 742887b..6e47b1b 100644 --- a/Koinex/Koinex.swift +++ b/Koinex/Koinex.swift @@ -16,7 +16,7 @@ public extension CurrencyPair { public struct Koinex { - public class Store: ExchangeDataStore { + public class Store: ExchangeDataStore { public static var shared = Store() override private init() { diff --git a/Kraken/Kraken.swift b/Kraken/Kraken.swift index 22bd47b..c68e5f9 100644 --- a/Kraken/Kraken.swift +++ b/Kraken/Kraken.swift @@ -33,7 +33,7 @@ public struct Kraken { super.init(symbol: symbol, price: lastPrice) } } - + public class Balance: Cryptex.Balance { public let type: String @@ -48,7 +48,7 @@ public struct Kraken { } } - public class Store: ExchangeDataStore { + public class Store: ExchangeDataStore { public static var shared = Store() override private init() { diff --git a/Poloniex/Poloniex.swift b/Poloniex/Poloniex.swift index 5c655fc..d24b13b 100644 --- a/Poloniex/Poloniex.swift +++ b/Poloniex/Poloniex.swift @@ -134,7 +134,7 @@ public struct Poloniex { status = json["status"] as? String ?? "" } } - + public struct Withdrawal { public var withdrawalNumber: Int public var currency: Currency @@ -155,7 +155,7 @@ public struct Poloniex { } } - public class Store: ExchangeDataStore { + public class Store: ExchangeDataStore { public static var shared = Store() override private init() { From 4fd278494eab75543cf00c2b6061033057afdefd Mon Sep 17 00:00:00 2001 From: Terrick Mansur Date: Sat, 27 Jan 2018 19:12:39 +0100 Subject: [PATCH 3/4] Includes orderId in Cyptopia openOrders. --- Cryptopia/Cryptopia.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cryptopia/Cryptopia.swift b/Cryptopia/Cryptopia.swift index c9b3239..09129b2 100644 --- a/Cryptopia/Cryptopia.swift +++ b/Cryptopia/Cryptopia.swift @@ -106,6 +106,9 @@ public struct Cryptopia { override init(json: [String: Any]) { super.init(json: json) + if let orderId = json["OrderId"] { + self.id = String(describing: orderId) + } self.rate = NSDecimalNumber(json["Rate"]) self.amount = NSDecimalNumber(json["Amount"]) self.remaining = NSDecimalNumber(json["Remaining"]) From 886a07bff5a0419c640235478d8835910f1dfc12 Mon Sep 17 00:00:00 2001 From: Terrick Mansur Date: Sun, 28 Jan 2018 21:17:05 +0100 Subject: [PATCH 4/4] Implements placeOrder for Cryptopia. --- Cryptopia/Cryptopia.swift | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Cryptopia/Cryptopia.swift b/Cryptopia/Cryptopia.swift index 09129b2..fb49574 100644 --- a/Cryptopia/Cryptopia.swift +++ b/Cryptopia/Cryptopia.swift @@ -179,6 +179,7 @@ public struct Cryptopia { // case getCurrencies case getTradePairs + case submitTrade(parameters: [String: String]) } public class Store: ExchangeDataStore { @@ -193,7 +194,7 @@ public struct Cryptopia { public var tickersResponse: HTTPURLResponse? = nil public var balanceResponse: HTTPURLResponse? = nil public var openOrdersResponse: HTTPURLResponse? = nil - + public var submitTrade: HTTPURLResponse? = nil public var currenciesResponse: (response: HTTPURLResponse?, currencies: [CryptopiaCurrency]) = (nil, []) } @@ -256,6 +257,15 @@ public struct Cryptopia { } } + public func submitTrade(parameters: [String:String], completion: @escaping (ResponseType, [[String: Any]], Error?) -> Void) { + let apiType = Cryptopia.API.submitTrade(parameters: parameters) + cryptopiaDataTaskFor(api: apiType) { (json, response, error) in + guard let json = json as? [[String: Any]] else { return } + self.store.openOrdersResponse = response + completion(.fetched, json, error) + }.resume() + } + public func getOpenOrders(completion: @escaping (ResponseType) -> Void) { let apiType = Cryptopia.API.getOpenOrders @@ -361,6 +371,7 @@ extension Cryptopia.API: APIType { case .getMarkets: return "/GetMarkets" case .getBalance: return "/GetBalance" case .getOpenOrders: return "/GetOpenOrders" + case .submitTrade: return "SubmitTrade" } } @@ -371,6 +382,7 @@ extension Cryptopia.API: APIType { case .getMarkets: return .GET case .getBalance: return .POST case .getOpenOrders: return .POST + case .submitTrade: return .POST } } @@ -381,6 +393,7 @@ extension Cryptopia.API: APIType { case .getMarkets: return false case .getBalance: return true case .getOpenOrders: return true + case .submitTrade: return true } } @@ -391,6 +404,7 @@ extension Cryptopia.API: APIType { case .getMarkets: return .url case .getBalance: return .url case .getOpenOrders: return .url + case .submitTrade: return .url } } @@ -401,6 +415,7 @@ extension Cryptopia.API: APIType { case .getMarkets: return [:] case .getBalance: return [:] case .getOpenOrders: return [:] + case .submitTrade(let parameters): return parameters } } @@ -411,6 +426,7 @@ extension Cryptopia.API: APIType { case .getMarkets: return .aMinute case .getBalance: return .aMinute case .getOpenOrders: return .aMinute + case .submitTrade: return .aMinute } } }