Skip to content

Commit

Permalink
OrderBase: WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
kosyloa committed Oct 10, 2023
1 parent 1a84c39 commit 342a921
Show file tree
Hide file tree
Showing 5 changed files with 249 additions and 2 deletions.
4 changes: 4 additions & 0 deletions DXFeedFramework.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@
648BD56F2AC582AB004A3A95 /* DateTimeParserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648BD56E2AC582AB004A3A95 /* DateTimeParserTest.swift */; };
648BD5712AC583AC004A3A95 /* TimeFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648BD5702AC583AC004A3A95 /* TimeFormat.swift */; };
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 */; };
6498E6B22AB1D41A0093A065 /* DXSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6498E6B12AB1D41A0093A065 /* DXSchedule.swift */; };
6498E6B52AB1D4480093A065 /* NativeSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6498E6B42AB1D4480093A065 /* NativeSchedule.swift */; };
Expand Down Expand Up @@ -648,6 +649,7 @@
648BD56E2AC582AB004A3A95 /* DateTimeParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTimeParserTest.swift; sourceTree = "<group>"; };
648BD5702AC583AC004A3A95 /* TimeFormat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeFormat.swift; sourceTree = "<group>"; };
648E98A92AAF625800BFD219 /* IIndexedEvent+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IIndexedEvent+Ext.swift"; sourceTree = "<group>"; };
649282EC2AD593F3008F0F04 /* OrderSourceTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderSourceTest.swift; sourceTree = "<group>"; };
64963B692A8E545C001E40F7 /* IEventType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IEventType.swift; sourceTree = "<group>"; };
6498E6B12AB1D41A0093A065 /* DXSchedule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DXSchedule.swift; sourceTree = "<group>"; };
6498E6B42AB1D4480093A065 /* NativeSchedule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeSchedule.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1373,6 +1375,7 @@
648BD56E2AC582AB004A3A95 /* DateTimeParserTest.swift */,
64098F662ACEB6F70020D741 /* DXConnectionStateTests.swift */,
6486B95C2AD0287E00D8D5FA /* DateTests.swift */,
649282EC2AD593F3008F0F04 /* OrderSourceTest.swift */,
);
path = DXFeedFrameworkTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -2211,6 +2214,7 @@
6447A5ED2A8FCC2200739CCF /* UtilsTest.swift in Sources */,
64278C6C2A602CA20074B5AA /* CandleTests.swift in Sources */,
6498E6B72AB1DACE0093A065 /* ScheduleTest.swift in Sources */,
649282ED2AD593F3008F0F04 /* OrderSourceTest.swift in Sources */,
6426C8932A531AB500236784 /* ThreadsTest.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
43 changes: 42 additions & 1 deletion DXFeedFramework/Events/Market/Extra/OrderBase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,19 @@
import Foundation

class OrderBase: MarketEvent, IIndexedEvent, CustomStringConvertible {
var eventSource: IndexedEventSource = .defaultSource

var type: EventCode = .orderBase

var eventSource: IndexedEventSource
// var eventSource: IndexedEventSource {
// get {
//
//
// }
// set {
//
// }
// }

var eventFlags: Int32 = 0

Expand Down Expand Up @@ -135,7 +145,38 @@ tradeSize: \(tradeSize)


extension OrderBase {
/// Gets a value indicating whether this order has some size
func hsaSize() -> Bool {
return size != 0 && !size.isNaN
}
/// Gets exchange code of this order.
public func getExchangeCode() -> Character {
return Character(BitUtil.getBits(flags: Int(flags), mask: OrderBase.exchangeMask, shift: OrderBase.exchangeShift))
}
/// Sets exchange code of this order.
///
/// - Throws: ``ArgumentException/exception(_:)``
public func setExchangeCode(_ code: Character) throws {
try StringUtil.checkChar(char: code, mask: OrderBase.exchangeMask, name: "exchangeCode")
if let value = code.unicodeScalars.first?.value {
flags = Int32(BitUtil.setBits(flags: Int(flags),
mask: OrderBase.exchangeMask,
shift: OrderBase.exchangeShift,
bits: Int(value)))
}
}

/// Gets or sets side of this order.
public var orderSide: Side {
get {
Side.valueOf(Int(BitUtil.getBits(flags: Int(flags), mask: OrderBase.sideMask, shift: OrderBase.sideShift)))
}
set {
flags = Int32(BitUtil.setBits(flags: Int(flags),
mask: OrderBase.sideMask,
shift: OrderBase.sideShift,
bits: newValue.rawValue))
}
}

}
144 changes: 143 additions & 1 deletion DXFeedFramework/Events/Market/Extra/OrderSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,148 @@

import Foundation

public class OrderSource : IndexedEventSource
/// Identifies source of ``Order``, ``AnalyticOrder``, ``OtcMarketsOrder`` and ``SpreadOrder`` events.
///
/// There are the following kinds of order sources:
///
/// Synthetic sources ``COMPOSITE_BID``, ``COMPOSITE_ASK``,
/// ``REGIONAL_BID``, and ``REGIONAL_ASK`` are provided for convenience of a consolidated
/// order book and are automatically generated based on the corresponding ``Quote`` events.
/// Aggregate sources ``AGGREGATE_BID`` and ``AGGREGATE_ASK`` provide
/// futures depth (aggregated by price level) and NASDAQ Level II (top of book for each market maker).
/// These source cannot be directly published to via dxFeed API.
/// ``isPublishable(Class) Publishable`` sources ``DEFAULT``, ``NTV``, and ``ISE``
/// support full range of dxFeed API features.
///
///

public class OrderSource: IndexedEventSource {
private static let pubOrder = 0x0001
private static let pubAnalyticOrder = 0x0002
private static let pubOtcMarketsOrder = 0x0004
private static let pubSpreadOrder = 0x0008
private static let fullOrderBook = 0x0010
private static let flagsSize = 5

private let pubFlags: Int
private let isBuiltin: Bool

static private let sourcesById = ConcurrentDict<Int, OrderSource>()
static private let sourcesByName = ConcurrentDict<String, OrderSource>()
private let sourcesByIdCache = NSCache<AnyObject, OrderSource>()

private override init(identifier: Int, name: String) {
self.pubFlags = 0
self.isBuiltin = false
super.init(identifier: identifier, name: name)
}

private init(identifier: Int, name: String, pubFlags: Int) throws {
self.pubFlags = pubFlags
self.isBuiltin = true
super.init(identifier: identifier, name: name)
switch identifier {
case _ where identifier < 0:
throw ArgumentException.exception("id is negative")
case _ where identifier > 0 && identifier < 0x20 && !OrderSource.isSpecialSourceId(sourceId: identifier):
throw ArgumentException.exception("id is not marked as special")
case _ where identifier > 0x20:
if try (identifier != OrderSource.composeId(name: name))
&& (name != OrderSource.decodeName(identifier: identifier)) {
throw ArgumentException.exception("id does not match name")
}
default:
print("")
}
// Flag FullOrderBook requires that source must be publishable.
if (pubFlags & OrderSource.fullOrderBook) != 0 && (pubFlags & (OrderSource.pubOrder | OrderSource.pubAnalyticOrder | OrderSource.pubSpreadOrder)) == 0 {
throw ArgumentException.exception("Unpublishable full order book order")
}

if !OrderSource.sourcesById.tryInsert(key: identifier, value: self) {
throw ArgumentException.exception("duplicate id")
}
if !OrderSource.sourcesByName.tryInsert(key: name, value: self) {
throw ArgumentException.exception("duplicate name")
}
}

/// Determines whether specified source identifier refers to special order source.
///Special order sources are used for wrapping non-order events into order events.
internal static func isSpecialSourceId(sourceId: Int) -> Bool {
return sourceId >= 1 && sourceId <= 6
}

internal static func composeId(name: String) throws -> Int {
var sourceId = 0
let count = name.count
if count == 0 || count > 4 {
return 0
}
for index in 0..<count {
let char = name[index]
try OrderSource.check(char: char)
sourceId = (sourceId << 8) | Int(char.first?.unicodeScalars.first?.value ?? 0)
}

return sourceId
}

internal static func check(char: String) throws {
if char.rangeOfCharacter(from: CharacterSet.alphanumerics.inverted) == nil {
return
}
throw ArgumentException.exception("Source name must contain only alphanumeric characters. Current \(char)")
}

internal static func decodeName(identifier: Int) throws -> String {
if identifier == 0 {
throw ArgumentException.exception("Source name must contain from 1 to 4 characters. Current \(identifier)")
}
var name = String()
for index in stride(from: 24, through: 0, by: -8) {
if identifier >> index == 0 { // Skip highest contiguous zeros.
continue
}
var char = Character(((identifier >> index) & 0xff))
try check(char: String(char))
name.append(char)
}
return name
}
/// Gets a value indicating whether this source supports Full Order Book.
public func isFullOrderBook() -> Bool {
return (pubFlags & OrderSource.fullOrderBook) != 0
}

/// Returns order source for the specified source identifier.
/// - Throws: ``ArgumentException/exception(_:)``. Rethrows exception from Java.
public static func valueOf(identifier: Int) throws -> OrderSource {
var source: OrderSource
if let source = sourcesById[identifier] {
return source
} else {
let name = try decodeName(identifier: identifier)
let source = OrderSource(identifier: identifier, name: name)
sourcesById[identifier] = source
return source
}
}
/// Returns order source for the specified source name.
///
/// The name must be either predefined, or contain at most 4 alphanumeric characters.
/// - Throws: ``ArgumentException/exception(_:)``. Rethrows exception from Java.
public static func valueOf(name: String) throws -> OrderSource {
var source: OrderSource
if let source = sourcesByName[name] {
return source
} else {
let identifier = try composeId(name: name)
let source = OrderSource(identifier: identifier, name: name)
sourcesByName[name] = source
return source
}

}

}
11 changes: 11 additions & 0 deletions DXFeedFramework/Utils/ConcurrentDict.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,17 @@ class ConcurrentDict<Key: Hashable, Value>: CustomStringConvertible {
writer { $0.removeAll() }
}

public func tryInsert(key: Key, value: Value) -> Bool {
var result = true
writer {
if $0[key] != nil {
result = false
}
$0[key] = value
}
return result
}

public func reader<U>(_ block: ([Key: Value]) throws -> U) rethrows -> U {
try accessQueue.sync { try block(set) }
}
Expand Down
49 changes: 49 additions & 0 deletions DXFeedFrameworkTests/OrderSourceTest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// OrderSourceTest.swift
// DXFeedFrameworkTests
//
// Created by Aleksey Kosylo on 10.10.23.
//

import XCTest
@testable import DXFeedFramework

final class OrderSourceTest: XCTestCase {

override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
}

override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}


func testIsSpecialSource() throws {
XCTAssert(OrderSource.isSpecialSourceId(sourceId: 1))
XCTAssert(!OrderSource.isSpecialSourceId(sourceId: 10))
XCTAssert(OrderSource.isSpecialSourceId(sourceId: 2))
}

func testCompose() throws {
let res = try OrderSource.composeId(name: "1234")
XCTAssert(res == 825373492)
}

func testCheckChar() throws {
do {
try OrderSource.check(char: "a")
} catch {
XCTAssert(false, "\(error)")
}
}

func testDecode() throws {
do {
let res = try OrderSource.decodeName(identifier: 1)
print(res)
} catch {
print("\(error)")
}
}
}

0 comments on commit 342a921

Please sign in to comment.