From 70f7f9442db9d0d1bb080268f734daf26dcd2343 Mon Sep 17 00:00:00 2001 From: kosyloa Date: Mon, 29 Apr 2024 13:26:33 +0200 Subject: [PATCH] feat: OnDemandSample --- DXFeedFramework.xcodeproj/project.pbxproj | 2 + DXFeedFramework/Utils/Date+Ext.swift | 4 +- .../OnDemandSample.playground/Contents.swift | 75 +++++++++++++++++++ .../contents.xcplayground | 4 + 4 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 Samples/Playgrounds/OnDemandSample.playground/Contents.swift create mode 100644 Samples/Playgrounds/OnDemandSample.playground/contents.xcplayground diff --git a/DXFeedFramework.xcodeproj/project.pbxproj b/DXFeedFramework.xcodeproj/project.pbxproj index e7e3ea30a..d12c03983 100644 --- a/DXFeedFramework.xcodeproj/project.pbxproj +++ b/DXFeedFramework.xcodeproj/project.pbxproj @@ -803,6 +803,7 @@ 64A42F4D2B0B9FA4001C3ACC /* DXTimeZone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DXTimeZone.swift; sourceTree = ""; }; 64A42F4F2B0BA668001C3ACC /* DXTimeFormat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DXTimeFormat.swift; sourceTree = ""; }; 64A42F512B0BBB6D001C3ACC /* DXTimePeriod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DXTimePeriod.swift; sourceTree = ""; }; + 64A631CF2BDFAA27002E1002 /* OnDemandSample.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = OnDemandSample.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 64AAF0522A8113E800E8942B /* String+Range.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Range.swift"; sourceTree = ""; }; 64AAF0542A82499A00E8942B /* ConcurrentDict.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConcurrentDict.swift; sourceTree = ""; }; 64AAF0562A82A3FC00E8942B /* ICandleSymbolProperty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ICandleSymbolProperty.swift; sourceTree = ""; }; @@ -1112,6 +1113,7 @@ 64F9C6C12B4BFD8F003ED014 /* DXFeedconnect.playground */, 644551C92B973A0D0069E3A2 /* FetchDailyCandles.playground */, 6433B1302BCE87D4004EFED7 /* RequestProfile.playground */, + 64A631CF2BDFAA27002E1002 /* OnDemandSample.playground */, 643A329C2BD15F2900F6F790 /* LastEventsConsole.playground */, ); path = Playgrounds; diff --git a/DXFeedFramework/Utils/Date+Ext.swift b/DXFeedFramework/Utils/Date+Ext.swift index a5ee18d11..f6aecb650 100644 --- a/DXFeedFramework/Utils/Date+Ext.swift +++ b/DXFeedFramework/Utils/Date+Ext.swift @@ -6,12 +6,12 @@ import Foundation -extension Date { +public extension Date { func millisecondsSince1970() -> TimeInterval { return timeIntervalSince1970 * 1000 } - func millisecondsSince1970() -> Int64 { + func millisecondsSince1970() -> Long { return Int64(timeIntervalSince1970 * 1000) } diff --git a/Samples/Playgrounds/OnDemandSample.playground/Contents.swift b/Samples/Playgrounds/OnDemandSample.playground/Contents.swift new file mode 100644 index 000000000..8f99be6e5 --- /dev/null +++ b/Samples/Playgrounds/OnDemandSample.playground/Contents.swift @@ -0,0 +1,75 @@ +import Cocoa +import DXFeedFramework + +// Empty Listener with handler +class Listener: DXEventListener, Hashable { + + static func == (lhs: Listener, rhs: Listener) -> Bool { + lhs === rhs + } + + func hash(into hasher: inout Hasher) { + hasher.combine("\(self):\(stringReference(self))") + } + var callback: ([MarketEvent]) -> Void = { _ in } + + func receiveEvents(_ events: [MarketEvent]) { + self.callback(events) + } + + init(overrides: (Listener) -> Listener) { + _ = overrides(self) + } +} + +do { + // get on-demand-only data feed + let onDemand = try OnDemandService.getInstance() + let feed = onDemand.getEndpoint()?.getFeed() + + // prepare time format + let timeZone = try DXTimeZone(timeZoneID: "America/New_York") + let defaultTimeFormat = try DXTimeFormat.init(timeZone: timeZone) + + // subscribe to Accenture symbol ACN to print its quotes + let subscription = try feed?.createSubscription(Quote.self) + + let listener = Listener { anonymCl in + anonymCl.callback = { events in + events.forEach { event in + if let quote = event as? Quote { + let time = (try? defaultTimeFormat.format(value: quote.eventTime)) ?? "" + print("\(time):bid \(quote.bidPrice) / ask \(quote.askPrice)") + } + } + } + return anonymCl + } + + try subscription?.add(listener: listener) + try subscription?.addSymbols("ACN") + + // Watch Accenture drop under $1 on May 6, 2010 "Flashcrash" from 14:47:48 to 14:48:02 EST + guard let fromDate: Date = try defaultTimeFormat.parse("2010-05-06 14:47:48.000 EST"), + let toDate: Date = try defaultTimeFormat.parse("2010-05-06 14:48:02.000 EST") else { + print("Couldn't parse date") + exit(-1) + } + + // switch into historical on-demand data replay mode + try onDemand.replay(date: fromDate) + + //// replaying events until end time reached + while (onDemand.getTime ?? Date.init(timeIntervalSince1970: 0)) < toDate { + if let time: Long = onDemand.getTime?.millisecondsSince1970() { + let timeStr = (try? defaultTimeFormat.format(value: time)) ?? "empty string" + let connectedState = (try? onDemand.getEndpoint()?.getState()) ?? .notConnected + print("Current state is \(connectedState), on-demand time is \(timeStr)") + } + Thread.sleep(forTimeInterval: 1000) + } + // close endpoint completely to release resources + try onDemand.getEndpoint()?.closeAndAwaitTermination() +} catch { + print("Exception during sample: \(error)") +} diff --git a/Samples/Playgrounds/OnDemandSample.playground/contents.xcplayground b/Samples/Playgrounds/OnDemandSample.playground/contents.xcplayground new file mode 100644 index 000000000..1c968e7d1 --- /dev/null +++ b/Samples/Playgrounds/OnDemandSample.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file