diff --git a/DXFeedFramework.xcodeproj/project.pbxproj b/DXFeedFramework.xcodeproj/project.pbxproj index 07de52ece..6b9597245 100644 --- a/DXFeedFramework.xcodeproj/project.pbxproj +++ b/DXFeedFramework.xcodeproj/project.pbxproj @@ -214,6 +214,7 @@ 648E98AA2AAF625800BFD219 /* IIndexedEvent+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648E98A92AAF625800BFD219 /* IIndexedEvent+Ext.swift */; }; 649282ED2AD593F3008F0F04 /* OrderSourceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649282EC2AD593F3008F0F04 /* OrderSourceTest.swift */; }; 64963B6A2A8E545C001E40F7 /* IEventType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64963B692A8E545C001E40F7 /* IEventType.swift */; }; + 649706842AD82B070068FF88 /* Series.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649706832AD82B070068FF88 /* Series.swift */; }; 6498E6B22AB1D41A0093A065 /* DXSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6498E6B12AB1D41A0093A065 /* DXSchedule.swift */; }; 6498E6B52AB1D4480093A065 /* NativeSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6498E6B42AB1D4480093A065 /* NativeSchedule.swift */; }; 6498E6B72AB1DACE0093A065 /* ScheduleTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6498E6B62AB1DACE0093A065 /* ScheduleTest.swift */; }; @@ -663,6 +664,7 @@ 648E98A92AAF625800BFD219 /* IIndexedEvent+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IIndexedEvent+Ext.swift"; sourceTree = ""; }; 649282EC2AD593F3008F0F04 /* OrderSourceTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderSourceTest.swift; sourceTree = ""; }; 64963B692A8E545C001E40F7 /* IEventType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IEventType.swift; sourceTree = ""; }; + 649706832AD82B070068FF88 /* Series.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Series.swift; sourceTree = ""; }; 6498E6B12AB1D41A0093A065 /* DXSchedule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DXSchedule.swift; sourceTree = ""; }; 6498E6B42AB1D4480093A065 /* NativeSchedule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeSchedule.swift; sourceTree = ""; }; 6498E6B62AB1DACE0093A065 /* ScheduleTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleTest.swift; sourceTree = ""; }; @@ -935,6 +937,7 @@ 64BDDB1D2AD6CC6A00694210 /* Order.swift */, 64BDDB1F2AD6CC8300694210 /* AnalyticOrder.swift */, 64BDDB212AD6CC9A00694210 /* SpreadOrder.swift */, + 649706832AD82B070068FF88 /* Series.swift */, ); path = Market; sourceTree = ""; @@ -2189,6 +2192,7 @@ 64ACBCE82A28CF9700032C53 /* IndexedEventSubscriptionSymbol.swift in Sources */, 649F48882A615BED0016FDD1 /* CandleType.swift in Sources */, 64BDDB2E2AD7DC5E00694210 /* OrderMapper.swift in Sources */, + 649706842AD82B070068FF88 /* Series.swift in Sources */, 6447A5E52A8F736E00739CCF /* TimeUtil.swift in Sources */, 64C771FC2A94D7E9009868C2 /* TradingStatus.swift in Sources */, 642BE4D22A2F5D230052340A /* TimeAndSale.swift in Sources */, diff --git a/DXFeedFramework/Events/Market/Greeks.swift b/DXFeedFramework/Events/Market/Greeks.swift index 4ef003212..7a1a17232 100644 --- a/DXFeedFramework/Events/Market/Greeks.swift +++ b/DXFeedFramework/Events/Market/Greeks.swift @@ -118,18 +118,18 @@ extension Greeks { /// Returns string representation of this greeks fields. public func toString() -> String { return """ -Greeks{"\(eventSymbol) + -"eventTime=\(TimeUtil.toLocalDateString(millis: eventTime)), \ -"eventFlags=0x\(String(format: "%02X", eventFlags)), \ -"time=\(TimeUtil.toLocalDateString(millis: time)), \ -"sequence=\(self.getSequence()), + -"price=\(price), \ -"volatility=\(volatility), \ -"delta=\(delta), + -"gamma=\(gamma), \ -"theta=\(theta), \ -"rho=\(rho), \ -"vega=\(vega)} +Greeks{\(eventSymbol), \ +eventTime=\(TimeUtil.toLocalDateString(millis: eventTime)), \ +eventFlags=0x\(String(format: "%02X", eventFlags)), \ +time=\(TimeUtil.toLocalDateString(millis: time)), \ +sequence=\(self.getSequence()), \ +price=\(price), \ +volatility=\(volatility), \ +delta=\(delta), \ +gamma=\(gamma), \ +theta=\(theta), \ +rho=\(rho), \ +vega=\(vega)} """ } } diff --git a/DXFeedFramework/Events/Market/Series.swift b/DXFeedFramework/Events/Market/Series.swift new file mode 100644 index 000000000..650875669 --- /dev/null +++ b/DXFeedFramework/Events/Market/Series.swift @@ -0,0 +1,125 @@ +// +// Series.swift +// DXFeedFramework +// +// Created by Aleksey Kosylo on 12.10.23. +// + +import Foundation + +/// Series event is a snapshot of computed values that are available for all option series for +/// a given underlying symbol based on the option prices on the market. +/// +/// It represents the most recent information that is available about the corresponding values on +/// the market at any given moment of time. +/// +/// (For more details see)[https://docs.dxfeed.com/dxfeed/api/com/dxfeed/event/option/Series.html] +public class Series: MarketEvent, IIndexedEvent { + public var type: EventCode = .series + + public var eventSource: IndexedEventSource = .defaultSource + + public var eventFlags: Int32 = 0 + + public var index: Long = 0 + + public var eventSymbol: String + + public var eventTime: Int64 = 0 + + /* + * EventFlags property has several significant bits that are packed into an integer in the following way: + * 31..7 6 5 4 3 2 1 0 + * \---------+----+----+----+----+----+----+----+ + * | | SM | | SS | SE | SB | RE | TX | + * \---------+----+----+----+----+----+----+----+ + */ + + /// Gets or sets time and sequence of this series packaged into single long value. + /// + /// This method is intended for efficient series time priority comparison. + /// **Do not use this method directly** + /// Change ``time`` and/or ``sequence`` + public private(set) var timeSequence: Long = 0 + /// Gets or sets day id of expiration. + public let expiration: Int32 = 0 + /// Gets or sets implied volatility index for this series based on VIX methodology. + public let volatility: Double = .nan + /// Gets or sets call options traded volume for a day. + public let callVolume: Double = .nan + /// Gets or sets put options traded volume for a day. + public let putVolume: Double = .nan + /// Gets or sets ratio of put options traded volume to call options traded volume for a day. + public let putCallRatio: Double = .nan + /// Gets or sets implied forward price for this option series. + public let forwardPrice: Double = .nan + /// Gets or sets implied simple dividend return of the corresponding option series. + public let dividend: Double = .nan + /// Gets or sets implied simple interest return of the corresponding option series. + public let interest: Double = .nan + + public init(_ eventSymbol: String) { + self.eventSymbol = eventSymbol + } +} + +extension Series { + /// Gets or sets timestamp of the event in milliseconds. + /// Time is measured in milliseconds between the current time and midnight, January 1, 1970 UTC. + public var time: Long { + get { + ((timeSequence >> 32) * 1000) + ((timeSequence >> 22) & 0x3ff) + } + set { + timeSequence = Long(TimeUtil.getSecondsFromTime(newValue) << 32) | + (Long(TimeUtil.getMillisFromTime(newValue)) << 22) | + Int64(getSequence()) + } + } + /// Gets sequence number of this event to distinguish events that have the same ``time``. + /// This sequence number does not have to be unique and + /// does not need to be sequential. Sequence can range from 0 to ``MarketEventConst/maxSequence``. + public func getSequence() -> Int { + return Int(timeSequence) & Int(MarketEventConst.maxSequence) + } + /// Sets sequence number of this event to distinguish quotes that have the same ``time``. + /// This sequence number does not have to be unique and + /// does not need to be sequential. Sequence can range from 0 to ``MarketEventConst/maxSequence``. + /// - Throws: ``ArgumentException/exception(_:)`` + public func setSequence(_ sequence: Int) throws { + if sequence < 0 || sequence > MarketEventConst.maxSequence { + throw ArgumentException.exception( + "Sequence(\(sequence) is < 0 or > MaxSequence(\(MarketEventConst.maxSequence)" + ) + } + timeSequence = Long(timeSequence & ~Long(MarketEventConst.maxSequence)) | Long(sequence) + } + + /// Gets options traded volume for a day. + public func getOptionVolume() -> Double { + if putVolume.isNaN { + return callVolume + } + return callVolume.isNaN ? putVolume : putVolume + putVolume; + } + + public func toString() -> String { + return +""" +Series{\(eventSymbol), \ +eventTime=\(TimeUtil.toLocalDateString(millis: eventTime)), \ +eventFlags=0x\(String(format: "%02X", eventFlags)), \ +index=0x\(String(format: "%02X", index)), \ +time=\(TimeUtil.toLocalDateString(millis: time)), \ +sequence=\(self.getSequence()), \ +expiration=\(DayUtil.getYearMonthDayByDayId(Int(expiration))), \ +volatility=\(volatility), \ +callVolume=\(callVolume), \ +putVolume=\(putVolume), \ +putCallRatio=\(putCallRatio), \ +forwardPrice=\(forwardPrice), \ +dividend=\(dividend), \ +interest=\(interest) +""" + } +} diff --git a/DXFeedFramework/Events/Market/Underlying.swift b/DXFeedFramework/Events/Market/Underlying.swift index 5cb4218f8..fffa659ae 100644 --- a/DXFeedFramework/Events/Market/Underlying.swift +++ b/DXFeedFramework/Events/Market/Underlying.swift @@ -110,13 +110,13 @@ extension Underlying { /// Returns string representation of this underlying fields. public func toString() -> String { return """ -Underlying{"\(eventSymbol) + +Underlying{"\(eventSymbol) \ eventTime=\(TimeUtil.toLocalDateString(millis: eventTime)), \ eventFlags=0x\(String(format: "%02X", eventFlags)), \ time=\(TimeUtil.toLocalDateString(millis: time)), \ -sequence=\(self.getSequence()), + +sequence=\(self.getSequence()), \ volatility=\(volatility), \ -frontVolatility=\(frontVolatility), + +frontVolatility=\(frontVolatility), \ backVolatility=\(backVolatility), \ callVolume=\(callVolume), \ putVolume=\(putVolume), \