Skip to content

Commit

Permalink
add samples:
Browse files Browse the repository at this point in the history
DxFeedFileParser
ConvertTapeFile
  • Loading branch information
kosyloa committed Dec 4, 2023
1 parent e0abce2 commit 34dec3c
Show file tree
Hide file tree
Showing 9 changed files with 297 additions and 4 deletions.
12 changes: 12 additions & 0 deletions DXFeedFramework.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,8 @@
644BD7652A44727000A0BF99 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
644BD7682A44727000A0BF99 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
644BD7882A4475EF00A0BF99 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainAR.storyboard; sourceTree = "<group>"; };
644C528D2B1E1CB8002C034C /* ConvertTapeFile.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = ConvertTapeFile.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
644C528F2B1E1D73002C034C /* DxFeedFileParser.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = DxFeedFileParser.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
644FE5D02AC1F34000580E3A /* LatencyMetricsPrinter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LatencyMetricsPrinter.swift; sourceTree = "<group>"; };
645A34942A937C7200709F29 /* BinaryInteger+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BinaryInteger+Ext.swift"; sourceTree = "<group>"; };
645BE8512AC31E7C0028243D /* PerfTestTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PerfTestTool.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -997,6 +999,15 @@
path = Market;
sourceTree = "<group>";
};
641E45FD2B1DF67E00649363 /* Playgrounds */ = {
isa = PBXGroup;
children = (
644C528F2B1E1D73002C034C /* DxFeedFileParser.playground */,
644C528D2B1E1CB8002C034C /* ConvertTapeFile.playground */,
);
path = Playgrounds;
sourceTree = "<group>";
};
64262CCA2A4DA64700BA6BA3 /* VisionQuoteTableApp */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1390,6 +1401,7 @@
64D8BB362A39B0DE0071BC88 /* Samples */ = {
isa = PBXGroup;
children = (
641E45FD2B1DF67E00649363 /* Playgrounds */,
6469F8D12A3B400100846831 /* Utils */,
64262CCA2A4DA64700BA6BA3 /* VisionQuoteTableApp */,
644BD75B2A44726F00A0BF99 /* ARQuoteTableApp */,
Expand Down
6 changes: 6 additions & 0 deletions DXFeedFramework/Events/EventCode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,9 @@ public enum EventCode: CaseIterable {
/// See ``OptionSale``
case optionSale
}

public extension EventCode {
static func unsupported() -> [EventCode] {
return [.dailyCandle, .configuration, .message, .orderBase]
}
}
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,12 +246,12 @@ sudo /usr/bin/xattr -r -d com.apple.quarantine <directory_with_tools>

## Samples

- [ ] ConvertTapeFile demonstrates how to convert one tape file to another tape file with optional intermediate processing or filtering
- [ ] DxFeedFileParser is a simple demonstration of how events are read form a tape file
- [x] ConvertTapeFile demonstrates how to convert one tape file to another tape file with optional intermediate processing or filtering
- [x] DxFeedFileParser is a simple demonstration of how events are read form a tape file
- [ ] DxFeedSample is a simple demonstration of how to create multiple event listeners and subscribe to `Quote` and `Trade` events
- [ ] PrintQuoteEvents is a simple demonstration of how to subscribe to the `Quote` event, using a `DxFeed` instance singleton and `dxfeed.properties` file
- [ ] WriteTapeFile is a simple demonstration of how to write events to a tape file
- [X] [DxFeedIpfConnect](https://github.com/dxFeed/dxfeed-graal-swift-api/blob/swift/Samples/Tools/IpfConnect.swift) is a simple demonstration of how to get Instrument Profiles
- [x] [DxFeedIpfConnect](https://github.com/dxFeed/dxfeed-graal-swift-api/blob/swift/Samples/Tools/IpfConnect.swift) is a simple demonstration of how to get Instrument Profiles
- [x] [DXFeedLiveIpfSample](https://github.com/dxFeed/dxfeed-graal-swift-api/blob/swift/Samples/Tools/LiveIpfSample.swift)
is a simple demonstration of how to get live updates for Instrument Profiles
- [ ] DxFeedPublishProfiles is a simple demonstration of how to publish market events
Expand Down
96 changes: 96 additions & 0 deletions Samples/Playgrounds/ConvertTapeFile.playground/Contents.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import Foundation
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)
}
}


let paths = Bundle.main.path(forResource: "ConvertTapeFile.in", ofType: nil)
let tempDirectory = NSTemporaryDirectory()
let fullURL = NSURL.fileURL(withPathComponents: [tempDirectory, "ConvertTapeFile.out"])?.path

// Determine input and output tapes and specify appropriate configuration parameters.
let inputAddress = "file:\(paths ?? "")[readAs=stream_data,speed=max]"
let outputAddress = "tape:\(fullURL ?? "" )[saveAs=stream_data,format=text]"

// Create input endpoint configured for tape reading.
let inputEndpoint = try DXEndpoint.builder()
.withRole(.streamFeed) // Prevents event conflation and loss due to buffer overflow.
.withProperty(DXEndpoint.Property.wildcardEnable.rawValue, "true") // Enables wildcard subscription.
.withProperty(DXEndpoint.Property.eventTime.rawValue, "true") // Use provided event times.
.build()

// Create output endpoint configured for tape writing.
var outputEndpoint = try DXEndpoint.builder()
.withRole(.streamPublisher) // Prevents event conflation and loss due to buffer overflow.
.withProperty(DXEndpoint.Property.wildcardEnable.rawValue, "true") // Enables wildcard subscription.
.withProperty(DXEndpoint.Property.eventTime.rawValue, "true") // Use provided event times.
.build()

// Create and link event processor for all types of events.
// Note: Set of processed event types could be limited if needed.
let eventTypes: [EventCode] = EventCode.allCases.compactMap { eventCode in
if EventCode.unsupported().contains(eventCode) {
return nil
} else {
return eventCode
}
}

let feed = inputEndpoint.getFeed()
let subscription = try feed?.createSubscription(eventTypes)

let listener = Listener { anonymCl in
anonymCl.callback = { events in
// Here event processing occurs. Events could be modified, removed, or new events added.
// For example, the below code adds 1 hour to event times:
// foreach (var e in events)
// {
// e.EventTime += 3600_000
// }

// Publish processed events
let publisher = outputEndpoint.getPublisher()
try? publisher?.publish(events: events)
}
return anonymCl
}

try subscription?.add(listener: listener)

// Subscribe to all symbols.
// Note: Set of processed symbols could be limited if needed.
try subscription?.addSymbols(WildcardSymbol.all)

// Connect output endpoint and start output tape writing BEFORE starting input tape reading.
try outputEndpoint.connect(outputAddress)
// Connect input endpoint and start input tape reading AFTER starting output tape writing.
try inputEndpoint.connect(inputAddress)

// Wait until all data is read and processed, and then gracefully close input endpoint.
try inputEndpoint.awaitNotConnected()
try inputEndpoint.closeAndAWaitTermination()

// Wait until all data is processed and written, and then gracefully close output endpoint.
try outputEndpoint.awaitProcessed()
try outputEndpoint.closeAndAWaitTermination()

print("ConvertTapeFile: \(inputAddress) has been successfully tapped to \(outputAddress)")
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
==DXP3 type=tape version=QDS-3.315 time=field +STREAM_DATA
==STREAM_DATA
=Quote EventSymbol EventTime BidTime BidExchangeCode BidPrice BidSize AskTime AskExchangeCode AskPrice AskSize
Quote AAPL 20230216-180402.785+0300 20230216-180402+0300 Q 153.94 2 20230216-180402+0300 Q 153.95 1
Quote AAPL 20230216-180402.805+0300 20230216-180402+0300 Q 153.94 2 20230216-180402+0300 Z 153.96 2
Quote AAPL 20230216-180402.871+0300 20230216-180402+0300 Q 153.94 2 20230216-180402+0300 Q 153.95 1
Quote AAPL 20230216-180402.878+0300 20230216-180402+0300 Q 153.94 2 20230216-180402+0300 Q 153.96 3
Quote AAPL 20230216-180402.922+0300 20230216-180402+0300 P 153.94 2 20230216-180402+0300 Q 153.96 4
Quote AAPL 20230216-180402.945+0300 20230216-180402+0300 P 153.94 2 20230216-180402+0300 Q 153.96 3
Quote AAPL 20230216-180402.954+0300 20230216-180402+0300 P 153.94 2 20230216-180402+0300 Q 153.96 2
Quote AAPL 20230216-180402.969+0300 20230216-180402+0300 P 153.94 2 20230216-180402+0300 Q 153.96 3
Quote AAPL 20230216-180402.989+0300 20230216-180402+0300 P 153.94 2 20230216-180402+0300 Q 153.95 1
Quote AAPL 20230216-180403.005+0300 20230216-180402+0300 P 153.94 2 20230216-180403+0300 Q 153.96 3
Quote AAPL 20230216-180403.010+0300 20230216-180402+0300 P 153.94 2 20230216-180403+0300 Q 153.96 4
Quote AAPL 20230216-180403.121+0300 20230216-180402+0300 P 153.94 2 20230216-180403+0300 Q 153.96 3
Quote AAPL 20230216-180403.149+0300 20230216-180402+0300 P 153.94 2 20230216-180403+0300 Q 153.95 1
Quote AAPL 20230216-180403.182+0300 20230216-180402+0300 P 153.94 2 20230216-180403+0300 Q 153.96 3
Quote AAPL 20230216-180403.245+0300 20230216-180402+0300 P 153.94 2 20230216-180403+0300 Q 153.96 4
Quote AAPL 20230216-180403.309+0300 20230216-180402+0300 P 153.94 2 20230216-180403+0300 Q 153.95 1
Quote AAPL 20230216-180403.353+0300 20230216-180402+0300 P 153.94 2 20230216-180403+0300 Z 153.96 3
Quote AAPL 20230216-180403.507+0300 20230216-180403+0300 Q 153.94 2 20230216-180403+0300 Q 153.96 3
Quote AAPL 20230216-180403.516+0300 20230216-180403+0300 Q 153.95 1 20230216-180403+0300 Z 153.96 1
Quote AAPL 20230216-180403.523+0300 20230216-180403+0300 Q 153.95 1 20230216-180403+0300 Q 153.96 1
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='macos' buildActiveScheme='true' importAppTypes='true'>
<timeline fileName='timeline.xctimeline'/>
</playground>
59 changes: 59 additions & 0 deletions Samples/Playgrounds/DxFeedFileParser.playground/Contents.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import Foundation
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)
}
}


var file: String = ""
var types: [EventCode] = [.quote]
var symbols = "AAPL"
var eventCounter = 0

// Create endpoint specifically for file parsing.
var endpoint = try DXEndpoint.create(.streamFeed)
var feed = endpoint.getFeed()

// Subscribe to a specified event and symbol.
var sub = try feed?.createSubscription(types)
let listener = Listener { anonymCl in
anonymCl.callback = { events in
events.forEach { event in
eventCounter += 1
print("\(eventCounter): \(event)")
}
}
return anonymCl
}
try sub?.add(listener: listener)

// Add symbols.
try sub?.addSymbols(symbols)

// Connect endpoint to a file.
try endpoint.connect("file:\(file)[speed=max]")

// Wait until file is completely parsed.
try endpoint.awaitNotConnected()

// Close endpoint when we're done.
// This method will gracefully close endpoint, waiting while data processing completes.
try endpoint.closeAndAWaitTermination()
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='macos' buildActiveScheme='true' importAppTypes='true'>
<timeline fileName='timeline.xctimeline'/>
</playground>
91 changes: 90 additions & 1 deletion Samples/Tools/ConnectTool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Where:

func execute() {
isQuite = arguments.isQuite

print(FileManager.default.currentDirectoryPath)
arguments.properties.forEach { key, value in
try? SystemProperty.setProperty(key, value)
}
Expand Down Expand Up @@ -104,4 +104,93 @@ Where:
// Print till input new line
_ = readLine()
}

func testConverTapeFile() throws {
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)
}
}


// Determine input and output tapes and specify appropriate configuration parameters.
let inputAddress = "file:/Users/akosylo/Projects/tapeK2.tape[readAs=stream_data,speed=max]"
let outputAddress = "tape:/Users/akosylo/Projects/tapeK21.tape[saveAs=stream_data,format=text]"

// Create input endpoint configured for tape reading.
let inputEndpoint = try DXEndpoint.builder()
.withRole(.streamFeed) // Prevents event conflation and loss due to buffer overflow.
.withProperty(DXEndpoint.Property.wildcardEnable.rawValue, "true") // Enables wildcard subscription.
.withProperty(DXEndpoint.Property.eventTime.rawValue, "true") // Use provided event times.
.build()

// Create output endpoint configured for tape writing.
var outputEndpoint = try DXEndpoint.builder()
.withRole(.streamPublisher) // Prevents event conflation and loss due to buffer overflow.
.withProperty(DXEndpoint.Property.wildcardEnable.rawValue, "true") // Enables wildcard subscription.
.withProperty(DXEndpoint.Property.eventTime.rawValue, "true") // Use provided event times.
.build()

// Create and link event processor for all types of events.
// Note: Set of processed event types could be limited if needed.
let eventTypes: [EventCode] = EventCode.allCases.compactMap { eventCode in
if EventCode.unsupported().contains(eventCode) {
return nil
} else {
return eventCode
}
}

let feed = inputEndpoint.getFeed()
let subscription = try feed?.createSubscription(eventTypes)

let listener = Listener { anonymCl in
anonymCl.callback = { events in
// Here event processing occurs. Events could be modified, removed, or new events added.
// For example, the below code adds 1 hour to event times:
// foreach (var e in events)
// {
// e.EventTime += 3600_000
// }

// Publish processed events
// let publisher = outputEndpoint.getPublisher()
// try? publisher?.publish(events: events)
}
return anonymCl
}

try subscription?.add(listener: listener)

// Subscribe to all symbols.
// Note: Set of processed symbols could be limited if needed.
try subscription?.addSymbols(WildcardSymbol.all)

// Connect output endpoint and start output tape writing BEFORE starting input tape reading.
try outputEndpoint.connect(outputAddress)
// Connect input endpoint and start input tape reading AFTER starting output tape writing.
try inputEndpoint.connect(inputAddress)

// Wait until all data is read and processed, and then gracefully close input endpoint.
try inputEndpoint.awaitNotConnected()
try inputEndpoint.closeAndAWaitTermination()

// Wait until all data is processed and written, and then gracefully close output endpoint.
try outputEndpoint.awaitProcessed()
try outputEndpoint.closeAndAWaitTermination()
}
}

0 comments on commit 34dec3c

Please sign in to comment.