Skip to main content

Quotes Data Provider

Quotes Data Provider provides data with selected trading instrument's candles that needs to be displayed on the chart AND quotes for the selected instrument, including Bid and Ask prices.

import Combine
/// Interface for receiving quotes data used in the DXChart framework.
///
/// When loading a chart in the DXChart framework, quotes data is sourced from this interface.
///
/// - Use `dataPublisher` to supply quotes data.
/// - Use `changeSymbol` to change the instrument symbol for which quotes are being provided.
public protocol QuotesDataProvider {
/// Publisher that provides quotes data.
///
/// The quotes data is represented by the `Quote` structure. This publisher emits the latest `Quote` data, and a `nil` value if no data is available.
var dataPublisher: AnyPublisher<Quote?, Never> { get }
/// Changes the instrument symbol for which quotes are being provided.
///
/// - Parameter symbol: The instrument symbol (e.g., "AAPL", "TSLA") for which the quotes data should be fetched.
func changeSymbol(_ symbol: String)
}

Candle model includes next parameters:

/// Represents a financial market candle (OHLCV data) for a specific time period.
///
/// The `Candle` structure holds data related to a specific time period, commonly used in financial charts to represent price movement.
/// It includes open, high, low, and close prices, along with volume, timestamp, and optional VWAP (volume-weighted average price).
///
/// - Commonly used in candlestick charts to show price movement within a given time interval.
public struct Candle: Codable, Hashable {
/// The closing price of the asset for the specific time period.
public var close: Double
/// The highest price reached during the specific time period.
public var hi: Double
/// The lowest price reached during the specific time period.
public var lo: Double
/// The opening price of the asset for the specific time period.
public var open: Double
/// The timestamp (in milliseconds since epoch) representing the start of the time period.
///
/// This timestamp is often used to place the candle in the correct position in a time-based chart.
public var timestamp: Int64
/// The trading volume (number of units traded) during the specific time period.
public var volume: Double
/// The volume-weighted average price (VWAP) for the specific time period.
///
/// VWAP is an optional value that represents the average price weighted by volume. It helps indicate the true average price over the time period.
public var vwap: Double?
}
/// ⚠️ Deprecated ⚠️
public typealias CandlesResponse = Candle

Possible Connection States:

/// Represents the connection state.
///
/// The "ConnectionState" enum defines the various states that a data connection can be in.
/// This is useful for monitoring and handling the lifecycle of data feeds, such as connecting to a remote service,
/// handling connection issues, and managing disconnections.
public enum ConnectionState {
/// The connection is not yet established.
///
/// This state indicates that no attempt to connect has been made, or that a previous connection was closed and has not yet attempted to reconnect.
case notConnected
/// The connection is currently being established.
///
/// This state is used when a connection attempt is in progress, but has not yet been completed.
case connecting
/// The connection is successfully established.
///
/// This state indicates that the connection to the data provider is active, and data can be received.
case connected
/// The connection has been closed.
///
/// This state is used when the connection was explicitly or automatically terminated.
case closed
}

QuoteResultDelegate

public protocol QuoteResultDelegate: AnyObject {
func updateConnectionState(_ state: ConnectionState)
func update(ask: Double, bid: Double)
}

func update(ask: Double, bid: Double) - a function to update bid and ask values on trading buttons.

Default provider

If you haven't implemented a Quote data provider earlier and are using DXFeedFramework to retrieve data, you can use our default provider. To work with it and DXFeedFramework, you need a Quote Address to obtain candles and quotes data. Please contact your DXFeed sales manager or visit https://dxfeed.com/contact-sales/ for more information.

Default implementation code:

import Combine
import DXChart
import DXFeedFramework
final class DXFeedQuotesDataProvider: DXChart.QuotesDataProvider {
let address: String
private var endpoint: DXEndpoint?
private var quoteSubscription: DXFeedSubscription?
private var symbol: String
init(address: String, symbol: String) {
self.address = address
self.symbol = symbol
}
private let _dataPublisher = PassthroughSubject<DXChart.Quote?, Never>()
lazy var dataPublisher: AnyPublisher<DXChart.Quote?, Never> = Deferred { [unowned self] in
self.connect()
return _dataPublisher
}.eraseToAnyPublisher()
func changeSymbol(_ symbol: String) {
self.symbol = symbol
reconnect()
}
private func connect() {
if endpoint == nil {
endpoint = try? DXEndpoint.builder().withRole(.feed)
.build()
endpoint?.add(listener: self)
_ = try? endpoint?.connect(address)
}
quoteSubscription = try? endpoint?.getFeed()?.createSubscription(Quote.self)
try? quoteSubscription?.add(listener: self)
try? quoteSubscription?.addSymbols(symbol)
}
private func disconnect() {
quoteSubscription?.remove(listener: self)
quoteSubscription = nil
}
private func reconnect() {
disconnect()
connect()
}
}
extension DXFeedQuotesDataProvider: Hashable {
static func == (lhs: DXFeedQuotesDataProvider, rhs: DXFeedQuotesDataProvider) -> Bool {
return lhs === rhs || lhs.address == rhs.address
}
public func hash(into hasher: inout Hasher) {
hasher.combine(address)
}
}
extension DXFeedQuotesDataProvider: DXEventListener {
func receiveEvents(_ events: [DXFeedFramework.MarketEvent]) {
let lastEvent = events.last
guard lastEvent?.type == .quote, let quote = lastEvent?.quote else { return }
_dataPublisher.send(.init(from: quote))
}
}
extension DXFeedQuotesDataProvider: DXEndpointListener {
public func endpointDidChangeState(old: DXFeedFramework.DXEndpointState, new: DXFeedFramework.DXEndpointState) {
// ignore this state
}
}
extension DXChart.Quote {
init(from qoute: DXFeedFramework.Quote) {
self.init(bidPrice: qoute.bidPrice, askPrice: qoute.askPrice)
}
}