Skip to content

Commit

Permalink
Merge branch 'swift' into feature/canle_charts
Browse files Browse the repository at this point in the history
# Conflicts:
#	DXFeedFramework/Native/Utils/NativeTimeUtil.swift
  • Loading branch information
kosyloa committed Jun 18, 2024
2 parents 3cd5e54 + 6fdbc95 commit c484fc8
Show file tree
Hide file tree
Showing 20 changed files with 279 additions and 25 deletions.
4 changes: 4 additions & 0 deletions DXFeedFramework.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1017,6 +1017,8 @@
64F73BA32B67B28B0088EC37 /* NativePromise.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativePromise.swift; sourceTree = "<group>"; };
64F73BA52B67CD5B0088EC37 /* GraalException+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GraalException+Ext.swift"; sourceTree = "<group>"; };
64F9C6C12B4BFD8F003ED014 /* DXFeedconnect.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = DXFeedconnect.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
64FDD7B62C21A09000D4469B /* DxFeedReconnectSample.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = DxFeedReconnectSample.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
64FDD7B72C21AF9D00D4469B /* SimpleAuthSample.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = SimpleAuthSample.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
803BAC0D29BFA50700FFAB1C /* DXFeedFramework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DXFeedFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; };
803BAC1029BFA50700FFAB1C /* DxFeedSwiftFramework.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DxFeedSwiftFramework.h; sourceTree = "<group>"; };
803BAC1529BFA50700FFAB1C /* DXFeedFrameworkTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DXFeedFrameworkTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -1237,6 +1239,8 @@
6433B1302BCE87D4004EFED7 /* RequestProfile.playground */,
64A631CF2BDFAA27002E1002 /* OnDemandSample.playground */,
643A329C2BD15F2900F6F790 /* LastEventsConsole.playground */,
64FDD7B62C21A09000D4469B /* DxFeedReconnectSample.playground */,
64FDD7B72C21AF9D00D4469B /* SimpleAuthSample.playground */,
);
path = Playgrounds;
sourceTree = "<group>";
Expand Down
4 changes: 2 additions & 2 deletions DXFeedFramework/Api/Osub/TimeSeriesSubscriptionSymbol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class TimeSeriesSubscriptionSymbol: GenericIndexedEventSubscriptionSymbol
/// - symbol: The event symbol.
/// - date: Date. Just for easing initialization with date object
convenience public init(symbol: AnyHashable, date: Date) {
self.init(symbol: symbol, fromTime: Long(date.timeIntervalSince1970) * 1000)
self.init(symbol: symbol, fromTime: date.millisecondsSince1970)
}

/// Initializes a new instance of the ``TimeSeriesSubscriptionSymbol`` class
Expand All @@ -43,7 +43,7 @@ public class TimeSeriesSubscriptionSymbol: GenericIndexedEventSubscriptionSymbol
/// - symbol: The event ``Symbol``
/// - date: Date. Just for easing initialization with date object
convenience public init(symbol: Symbol, date: Date) {
self.init(symbol: symbol.stringValue, fromTime: Long(date.timeIntervalSince1970) * 1000)
self.init(symbol: symbol.stringValue, fromTime: date.millisecondsSince1970)
}

static func == (lhs: TimeSeriesSubscriptionSymbol, rhs: TimeSeriesSubscriptionSymbol) -> Bool {
Expand Down
2 changes: 1 addition & 1 deletion DXFeedFramework/Events/Market/Candles/Candle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public class Candle: MarketEvent, ITimeSeriesEvent, ILastingEvent, CustomStringC
"""
DXFG_CANDLE_T \
eventSymbol: \(eventSymbol) \
eventTime: \(Date(timeIntervalSince1970: TimeInterval(Double(time/1000)))) \
eventTime: \(Date(millisecondsSince1970: time))) \
eventSymbol: \(eventSymbol), \
eventTime: \(eventTime), \
eventFlags: \(eventFlags), \
Expand Down
2 changes: 1 addition & 1 deletion DXFeedFramework/Ipf/InstrumentProfileField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ extension InstrumentProfileField {
guard let date = dateFormatter.date(from: value) else {
return 0
}
parsedDates[value] = Entry(text: value, binary: date.millisecondsSince1970() / TimeUtil.day)
parsedDates[value] = Entry(text: value, binary: date.millisecondsSince1970 / TimeUtil.day)
return parsedDates[value]?.binary ?? 0
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,15 @@ class NativeOnDemandService {
try ErrorCheck.nativeCall(thread,
dxfg_OnDemandService_replay(thread,
native,
date.millisecondsSince1970()))
date.millisecondsSince1970))
}

func replay(date: Date, speed: Double) throws {
let thread = currentThread()
try ErrorCheck.nativeCall(thread,
dxfg_OnDemandService_replay2(thread,
native,
date.millisecondsSince1970(),
date.millisecondsSince1970,
speed))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class NativeTimeSeriesSubscription {
_ = try ErrorCheck.nativeCall(thread, dxfg_DXFeedTimeSeriesSubscription_setFromTime(
thread,
native,
0))
fromTime))
}

}
2 changes: 1 addition & 1 deletion DXFeedFramework/OnDemand/OnDemandService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public class OnDemandService {
/// Changes on-demand historical data replay speed while continuing replay at current ``getTime``.
/// Speed is measured with respect to the real-time playback speed.
/// - Parameters:
/// - speed: on-demand historical data replay speed.
/// - speed: on-demand historical data replay speed. Should be > 0.
/// - Throws: ``GraalException``. Rethrows exception from Java.
public func setSpeed(_ speed: Double) throws {
try native.setSpeed(speed)
Expand Down
11 changes: 5 additions & 6 deletions DXFeedFramework/Utils/Date+Ext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@
import Foundation

public extension Date {
func millisecondsSince1970() -> TimeInterval {
return timeIntervalSince1970 * 1000
}

func millisecondsSince1970() -> Long {
return Int64(timeIntervalSince1970 * 1000)
}
public var millisecondsSince1970: Long { Long(timeIntervalSince1970 * 1000) }

// func millisecondsSince1970 -> Long {
// return Int64(timeIntervalSince1970 * 1000)
// }

init(millisecondsSince1970: Long) {
self.init(timeIntervalSince1970: Double(millisecondsSince1970) / 1000)
Expand Down
2 changes: 1 addition & 1 deletion DXFeedFrameworkTests/DXAsyncLastTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ final class DXAsyncLastTest: XCTestCase {
let date = Calendar.current.date(byAdding: .month, value: -1, to: Date())!
guard let task = feed?.getTimeSeries(type: Candle.self,
symbol: "AAPL{=1d}",
fromTime: date.millisecondsSince1970(),
fromTime: date.millisecondsSince1970,
toTime: Long.max) else {
XCTAssert(false, "Async task is nil")
return
Expand Down
42 changes: 42 additions & 0 deletions DXFeedFrameworkTests/DXConnectionTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,48 @@ final class DXConnectionTest: XCTestCase {
wait(for: [receivedEventsExpectation], timeout: 20)
}

func testDXLinkConnectionTheoPrice() throws {
throw XCTSkip("Just for reflection testing")

// For token-based authorization, use the following address format:
// "dxlink:wss://demo.dxfeed.com/dxlink-ws[login=dxlink:token]"
let endpoint = try DXEndpoint.builder()
.build()

let subscription = try endpoint.getFeed()?.createSubscription(TheoPrice.self)
let receivedEventsExpectation = expectation(description: "Received events")
let eventListener = DXConnectionListener(expectation: receivedEventsExpectation)
try subscription?.add(listener: eventListener)
try subscription?.addSymbols(
TimeSeriesSubscriptionSymbol(symbol: ".AAPL240524C110", fromTime: 10)
)
try endpoint.connect("dxlink:wss://demo.dxfeed.com/dxlink-ws")
defer {
try? endpoint.closeAndAwaitTermination()
}
wait(for: [receivedEventsExpectation], timeout: 10)
}

func testDXLinkConnectionGreeks() throws {
throw XCTSkip("Just for reflection testing")

// For token-based authorization, use the following address format:
// "dxlink:wss://demo.dxfeed.com/dxlink-ws[login=dxlink:token]"
let endpoint = try DXEndpoint.builder()
.build()

let subscription = try endpoint.getFeed()?.createSubscription(Greeks.self)
let receivedEventsExpectation = expectation(description: "Received events")
let eventListener = DXConnectionListener(expectation: receivedEventsExpectation)
try subscription?.add(listener: eventListener)
try subscription?.addSymbols(".AAPL240524C110")
try endpoint.connect("dxlink:wss://demo.dxfeed.com/dxlink-ws")
defer {
try? endpoint.closeAndAwaitTermination()
}
wait(for: [receivedEventsExpectation], timeout: 10)
}

func testConnection() throws {
// For token-based authorization, use the following address format:
// "demo.dxfeed.com:7300[login=entitle:token]"
Expand Down
2 changes: 1 addition & 1 deletion DXFeedFrameworkTests/DXPromiseTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ final class DXPromiseTest: XCTestCase {

guard let promise = try feed?.getTimeSeriesPromise(type: Candle.self,
symbol: "AAPL{=1d}",
fromTime: date.millisecondsSince1970(),
fromTime: date.millisecondsSince1970,
toTime: Long.max) else {
XCTAssert(false, "Empty promise")
return
Expand Down
4 changes: 2 additions & 2 deletions DXFeedFrameworkTests/DXTimeSeriesSubscriptionTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ final class DXTimeSeriesSubscriptionTest: XCTestCase {
return anonymCl
}
try subscription?.add(listener: listener)
try subscription?.set(fromTime: 10000)
try subscription?.addSymbols(["ETH/USD:GDAX", "IBM"])
try subscription?.set(fromTime: 1717045200)
try subscription?.addSymbols(["AAPL{=8h}"])
wait(for: [receivedEventsExpectation], timeout: 3.0)
try endpoint.closeAndAwaitTermination()
}
Expand Down
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

import PackageDescription

let version = "1.0.1_build"
let version = "1.1.3_build"
let moduleName = "DXFeedFramework"
let checksum = "68a73daad279e200be8b54021725cceae5ad044359531c1130356d68bebdd3c1"
let checksum = "0529710169a58beb75042eb53f715ce529d88d01d05c03d57dde61fcc87bf1f5"

let package = Package(
name: moduleName,
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,11 @@ is a simple demonstration of how to get live updates for Instrument Profiles
- [x] [ScheduleSample](https://github.com/dxFeed/dxfeed-graal-swift-api/blob/swift/Samples/Playgrounds/ScheduleSample.playground/Contents.swift)
is a simple demonstration of how to get various scheduling information for instruments
- [x] [FetchDailyCandles](https://github.com/dxFeed/dxfeed-graal-swift-api/blob/swift/Samples/Playgrounds/FetchDailyCandles.playground/Contents.swift) is a simple demonstration of how to fetch last N-days of candles for a specified symbol
- [x] [DxFeedReconnectSample](https://github.com/dxFeed/dxfeed-graal-swift-api/blob/swift/Samples/Playgrounds/DxFeedReconnectSample.playground/Contents.swift)
is a simple demonstration of how to connect to an endpoint, subscribe to market data events, handle reconnections
and re-subscribing.
- [x] [SimpleAuthSample](https://github.com/dxFeed/dxfeed-graal-swift-api/blob/swift/Samples/Playgrounds/SimpleAuthSample.playground/Contents.swift)
is a simple demonstration of how to connect to endpoint requires authentication token, subscribe to market data events, and handle periodic token updates.

## Current State

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import Cocoa
import PlaygroundSupport
import DXFeedFramework

// Empty Event 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)
}
}

// Empty Endpoint Listener with handler
class EndpoointStateListener: DXEndpointListener, Hashable {
func endpointDidChangeState(old: DXFeedFramework.DXEndpointState, new: DXFeedFramework.DXEndpointState) {
callback(old, new)
}

static func == (lhs: EndpoointStateListener, rhs: EndpoointStateListener) -> Bool {
lhs === rhs
}

func hash(into hasher: inout Hasher) {
hasher.combine("\(self):\(stringReference(self))")
}
var callback: (DXEndpointState, DXEndpointState) -> Void = { _, _ in }

init(overrides: (EndpoointStateListener) -> EndpoointStateListener) {
_ = overrides(self)
}
}

// Demonstrates how to connect to an endpoint, subscribe to market data events,
// handle reconnections and re-subscribing.
let address = "demo.dxfeed.com:7300" // The address of the DxFeed endpoint.
let symbol = "ETH/USD:GDAX" // The symbol for which we want to receive quotes.

// Create new endpoint and add a listener for state changes.
let endpoint = try DXEndpoint.getInstance()
let stateListener = EndpoointStateListener { listener in
listener.callback = { old, new in
print("Connection state changed: \(old) -> \(new)")
}
return listener
}
endpoint.add(listener: stateListener)

// Connect to the endpoint using the specified address.
try endpoint.connect(address)

// Create a subscription for Quote events.
let subscriptionQuote = try endpoint.getFeed()?.createSubscription(Quote.self)
// Listener must be attached before symbols are added.
let listener = Listener { listener in
listener.callback = { events in
events.forEach { event in
print(event.toString())
}
}
return listener
}
try subscriptionQuote?.add(listener: listener)

// Add the specified symbol to the subscription.
try subscriptionQuote?.addSymbols(symbol)

// Wait for five seconds to allow some quotes to be received.
Thread.sleep(forTimeInterval: 5)

// Disconnect from the endpoint.
try endpoint.disconnect()

// Wait for another five seconds to ensure quotes stop coming in.
Thread.sleep(forTimeInterval: 5)

// Reconnect to the endpoint.
// The subscription is automatically re-subscribed, and quotes start coming into the listener again.
// Another address can also be passed on.
try endpoint.connect(address)

// infinity execution
PlaygroundPage.current.needsIndefiniteExecution = true

// to finish execution run this line
PlaygroundPage.current.finishExecution()
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>
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import DXFeedFramework
// await couldn't use directly in Playground(this is accompanied by errors like: execution stopped with unexpected state)
Task {
let baseSymbol = CandleSymbol.valueOf("AAPL", [CandlePeriod.day])
var toTime: Long = Long(Date.now.timeIntervalSince1970 * 1000)
let fromFime: Long = Long(Calendar.current.date(byAdding: .day,
var toTime: Long = Date.now.millisecondsSince1970
let fromFime: Long = Calendar.current.date(byAdding: .day,
value: -20,
to: Date())!.timeIntervalSince1970 * 1000)
to: Date())!.millisecondsSince1970
let endpoint = try DXEndpoint.getInstance().connect("demo.dxfeed.com:7300")
let feed = endpoint.getFeed()
guard let task = feed?.getTimeSeries(type: Candle.self,
Expand Down
4 changes: 2 additions & 2 deletions Samples/Playgrounds/OnDemandSample.playground/Contents.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ do {

//// replaying events until end time reached
while (onDemand.getTime ?? Date.init(timeIntervalSince1970: 0)) < toDate {
if let time: Long = onDemand.getTime?.millisecondsSince1970() {
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)
Thread.sleep(forTimeInterval: 1)
}
// close endpoint completely to release resources
try onDemand.getEndpoint()?.closeAndAwaitTermination()
Expand Down
Loading

0 comments on commit c484fc8

Please sign in to comment.