Skip to content

Commit

Permalink
sample: LastEventsConsole
Browse files Browse the repository at this point in the history
  • Loading branch information
kosyloa committed Apr 19, 2024
1 parent 8584012 commit 7ea077f
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 10 deletions.
2 changes: 2 additions & 0 deletions DXFeedFramework.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,7 @@
6433B1312BCFC01F004EFED7 /* DXLastEventsSubscribedTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DXLastEventsSubscribedTest.swift; sourceTree = "<group>"; };
6435EE3C2B1F1E9200E8496C /* PrintQuoteEvents.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = PrintQuoteEvents.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
643A329A2BD0137000F6F790 /* Optional+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+Ext.swift"; sourceTree = "<group>"; };
643A329C2BD15F2900F6F790 /* LastEventsConsole.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = LastEventsConsole.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
64437A8E2A9DEE6F005929B2 /* InstrumentProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstrumentProfile.swift; sourceTree = "<group>"; };
64437A912A9DF1DE005929B2 /* NativeInstrumentProfileReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeInstrumentProfileReader.swift; sourceTree = "<group>"; };
644551C92B973A0D0069E3A2 /* FetchDailyCandles.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = FetchDailyCandles.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
Expand Down Expand Up @@ -1103,6 +1104,7 @@
64F9C6C12B4BFD8F003ED014 /* DXFeedconnect.playground */,
644551C92B973A0D0069E3A2 /* FetchDailyCandles.playground */,
6433B1302BCE87D4004EFED7 /* RequestProfile.playground */,
643A329C2BD15F2900F6F790 /* LastEventsConsole.playground */,
);
path = Playgrounds;
sourceTree = "<group>";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
</CommandLineArgument>
<CommandLineArgument
argument = "PerfTest demo.dxfeed.com:7300 TimeAndSale,Quote,profile ETH/USD:GDAX,AAPL -p monitoring.stat=2s"
isEnabled = "YES">
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = " qds post :6666"
Expand All @@ -68,8 +68,8 @@
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "Connect demo.dxfeed.com:7300 TRADE ETH/USD:GDAX"
isEnabled = "NO">
argument = "Connect demo.dxfeed.com:7300 TRADE AAPL"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "qds connect demo.dxfeed.com:7300 TimeAndSale AAPL,AAPL2,IBM,ETH/USD:GDAX -p monitoring.stat=10s"
Expand Down
22 changes: 15 additions & 7 deletions DXFeedFramework/Native/Promise/NativePromise.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,13 @@ class NativePromise {
return results
}
let thread = currentThread()
let res = try promise?.withMemoryRebound(to: dxfg_promise_events_t.self, capacity: 1, { promiseEvents in
let listPointer = try ErrorCheck.nativeCall(thread,
let res: [MarketEvent]? = try promise?.withMemoryRebound(to: dxfg_promise_events_t.self,
capacity: 1, { promiseEvents in
guard let listPointer = try ErrorCheck.nativeCall(thread,
dxfg_Promise_List_EventType_getResult(thread,
promiseEvents)).value()
promiseEvents)) else {
return nil
}
defer {
_ = try? ErrorCheck.nativeCall(thread, dxfg_CList_EventType_release(thread, listPointer))
}
Expand All @@ -96,16 +99,21 @@ class NativePromise {
return result
}
let thread = currentThread()
let res = try promise?.withMemoryRebound(to: dxfg_promise_event_t.self, capacity: 1, { promiseEvent in
let result = try ErrorCheck.nativeCall(thread,
dxfg_Promise_EventType_getResult(thread,
promiseEvent)).value()
let res: MarketEvent? = try promise?.withMemoryRebound(to: dxfg_promise_event_t.self,
capacity: 1, { promiseEvent in
guard let result = try ErrorCheck.nativeCall(thread,
dxfg_Promise_EventType_getResult(thread,
promiseEvent)) else {
return nil
}

let marketEvent = try EventMapper().fromNative(native: result)
defer {
_ = try? ErrorCheck.nativeCall(thread, dxfg_EventType_release(thread, result))
}
self.result = marketEvent
return marketEvent

})
return res
}
Expand Down
109 changes: 109 additions & 0 deletions Samples/Playgrounds/LastEventsConsole.playground/Contents.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import PlaygroundSupport
import UIKit
import DXFeedFramework

/**
* This sample demonstrates a way to subscribe to the big world of symbols with dxFeed API, so that the events are
* updated and cached in memory of this process, and then take snapshots of those events from memory whenever
* they are needed. This example repeatedly reads symbol name from the console and prints a snapshot of its last
* quote, trade, summary, and profile events.
*/

let records = "Quote,Trade,Summary,Profile"
let symbols = "http://dxfeed.s3.amazonaws.com/masterdata/ipf/demo/mux-demo.ipf.zip"

let endpoint = try DXEndpoint.builder()
.withProperty("dxfeed.qd.subscribe.ticker", records + " " + symbols)
.build().connect("demo.dxfeed.com:7300")

guard let feed = endpoint.getFeed() else {
exit(-1)
}

func fetchData(feed: DXFeed, symbol: String) throws {
print("begin fetching for \(symbol)")

/*
* The first step is to extract promises for all events that we are interested in. This way we
* can get an event even if we have not previously subscribed for it.
*/
let qPromise = try feed.getLastEventPromise(type: Quote.self, symbol: symbol)
let tPromise = try feed.getLastEventPromise(type: Trade.self, symbol: symbol)
let sPromise = try feed.getLastEventPromise(type: Summary.self, symbol: symbol)
/*
* All promises are put into a list for convenience.
*/
var promises = [qPromise, tPromise, sPromise]
/*
* Profile events are composite-only. They are not available for regional symbols like
* "IBM&N" and the attempt to retrieve never completes (will timeout), so we don't event try.
*/
if !MarketEventSymbols.hasExchangeCode(symbol) {
var pPromise = try feed.getLastEventPromise(type: Profile.self, symbol: symbol)
promises.append(pPromise)
}

/*
* If the events are available in the in-memory cache, then the promises will be completed immediately.
* Otherwise, a request to the upstream data provider is sent. Below we combine promises using
* Promises utility class from DXFeed API in order to wait for at most 1 second for all of the
* promises to complete. The last event promise never completes exceptionally and we don't
* have to specially process a case of timeout, so "awaitWithoutException" is used to continue
* normal execution even on timeout. This sample prints a special message in the case of timeout.
*/
if try Promise.allOf(promises: promises)?.awaitWithoutException(millis: 1000) == false {
print("Request timed out")
}
/*
* The combination above is used only to ensure a common wait of 1 second. Promises to individual events
* are completed independently and the corresponding events can be accessed even if some events were not
* available for any reason and the wait above had timed out. This sample just prints all results.
* "null" is printed when the event is not available.
*/
try promises.forEach { pr in
print(try pr.getResult()?.toString() ?? "Null result for \(pr)")
}
print("end fetching for \(symbol)")
}

// Just UI for symbol input
class V: UIViewController {
var textField = UITextField()
var feed: DXFeed!

override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(textField)
textField.translatesAutoresizingMaskIntoConstraints = false

textField.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0).isActive = true
textField.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0).isActive = true
textField.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 15).isActive = true
textField.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -15).isActive = true
textField.placeholder = "Type symbols to get their quote, trade, summary, and profile event snapshots"
textField.delegate = self
}
}

extension V: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
do {
try fetchData(feed: feed, symbol: textField.text ?? "")
} catch {
print("Error during fetching: \(error)")
}
textField.text = ""
return true
}
}

let view = V()
view.feed = feed
view.view.frame = CGRect(x: 0, y: 0, width: 400, height: 150)


PlaygroundPage.current.liveView = view.view
PlaygroundPage.current.needsIndefiniteExecution = true



Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='ios' buildActiveScheme='true' importAppTypes='true'>
<timeline fileName='timeline.xctimeline'/>
</playground>

0 comments on commit 7ea077f

Please sign in to comment.