createMktDataEngine

Syntax

createMktDataEngine(name, referenceDate, mktDataConfig, [handler], [historicalData], [engineConfig])

Details

Creates a real-time market data construction engine (for curves, surfaces, etc.).

The engine automatically builds market data such as curves and surfaces based on the given configuration, and supports both historical data backfilling and real-time data updates.

Parameters

name is a string indicating the name of the engine. It is the only identifier of an engine on a data or compute node. It can have letter, number and "_" and must start with a letter.

referenceDate is a DATE scalar indicating the reference date of the market data.

mktDataConfig A dictionary or a tuple of dictionaries. Specifies the market data construction configuration. See below for details on the configuration format.

handler (optional) is used to handle the results of market data construction. It can be a user-defined function, a shared in-memory table, or a pricing engine. The function signature or table schema depends on engineConfig.outputTime:

  • engineConfig.outputTime=false:The user-defined function takes parameters (kind, date, name, data); the shared in-memory table must contain four columns: kind (STRING), date (DATE), name (STRING), and data (MKTDATA).
  • engineConfig.outputTime=true:The user-defined function takes parameters (eventTime, kind, date, name, data); the shared in-memory table must contain five columns: eventTime (NANOTIMESTAMP), kind (STRING), date (DATE), name (STRING), and data (MKTDATA).

historicalData (optional) is the historical market data. If the required market data cannot be obtained from the engine cache or real-time streams during construction, the engine will retrieve data from this source. It can be:

  • A dictionary or vector: refer to the marketData parameter in the instrumentPricer function for the data format.
  • A user-defined function: the function parameters are (kind, date, name).

engineConfig (optional) is a dictionary specifying engine runtime configuration. Supported key-value pairs include:

  • numThreads (optional): is an INT scalar indicating the number of worker threads. Default is 8.
  • maxQueueDepth (optional): is an INT scalar indicating the maximum queue depth. Default is 10,000,000.
  • useSystemTime (optional): is a Boolean value indicating whether to use system time as the event time. Default is true.
  • timeColumn (optional) is a string to specify a NANOTIMESTAMP column as the event time. When specified, input data must contain this column.
  • outputTime (optional) is a Boolean value indicating whether to output the event time. Default is false.

Returns

Returns a handle of a market data engine.

mktDataConfig format and Data Insertion Schema

Foreign Exchange Spot Rate

The configuration fields for FX spot rates are specified in the table below:

Field Name Data Type Description Required
name STRING

Unit for spot prices. Available options: "EURUSD", "USDCNY", "EURCNY", "GBPCNY", "JPYCNY", "HKDCNY".

Currency pairs may also use . or / as separators. For example, "EURUSD" can also be written as "EUR.USD" or "EUR/USD".

type STRING Must be "FxSpotRate"

Configuration example

config = {
    "name": "USDCNY",
    "type": "FxSpotRate"
}

Description:

FX spot rate curves are automatically included during the construction of related curves or surfaces, such as cross-currency interest rate swap yield curves or foreign exchange volatility surfaces, and therefore does not need to be configured separately.

Only when an FX spot rate curve needs to be output independently is explicit configuration required. In this case, it is sufficient to provide a configuration dictionary as shown in the example above.

Data insertion schema

Column Name Data Type Description
type STRING Must be "FxSpotRate"
name STRING The currency pair, for example, “USDCNY” (the currency pair can be separated by . or /).
price DOUBLE Current price.

Note: When inserting data, the column names and data types must conform to the definitions in the table above. The column order is not required to be consistent.

Data insertion example

typeCol = ["FxSpot", "FxSpot", "FxSpot"]
nameCol = ["USDCNY", "EURCNY", "EURUSD"]
priceCol = [7.12, 7.88, 1.10]

data = table(typeCol as type, nameCol as name, priceCol as price)

Complete example

try{dropStreamEngine("MKTDATA_ENGINE")}catch(ex){}
referenceDate = 2025.01.01

config1 = {
    "name": "USDCNY",
    "type": "FxSpotRate"
}
config2 = {
    "name": "EURUSD",
    "type": "FxSpotRate"
}
config3 = {
    "name": "EURCNY",
    "type": "FxSpotRate"
}

engine = createMktDataEngine("MKTDATA_ENGINE", referenceDate, [config1, config2, config3])

typeCol = ["FxSpot", "FxSpot", "FxSpot"]
nameCol = ["USDCNY", "EURCNY", "EURUSD"]
priceCol = [7.12, 7.88, 1.10]

data = table(typeCol as type, nameCol as name, priceCol as price)

engine.append!(data)
sleep(100)
  • In this example, three build targets are created, representing the FX spot rates for USDCNY, EURUSD, and EURCNY.
  • The written data covers only two of these build targets, with a total of three records: two for USDCNY and one for EURUSD.
  • Data is written in asynchronous mode, so sufficient waiting time must be reserved to ensure that all data has been fully processed.

After the build process is completed, the constructed market data can be retrieved using the getMktData function.

re = getMktData(engine, "Price", referenceDate, "USDCNY")
print(re)

re = getMktData(engine, "Price", referenceDate, "EURUSD")
print(re)

re = getMktData(engine, "Price", referenceDate, "EURCNY")
print(re)

The result will return the latest market data for USDCNY and EURUSD. Since no data is written for EURCNY, calling getMktData for EURCNY will result in an error.

Bond Yield Curve

The mktDataConfig fields required for generating a bond yield curve include the following:

  • name: Required, the name of the curve.
  • type: Required, must be "BondYieldCurve"
  • bonds: Required, the sample bonds used for curve construction
  • currency: Required, the currency code of the curve
  • dayCountConvention: Required, the day count convention to use
  • compounding: Optional, the compounding method
  • frequency: Optional, the interest payment frequency
  • interpMethod: Optional, the interpolation method
  • extrapMethod: Optional, the extrapolation method
  • method: Optional, the curve construction method

All fields are consistent with those defined for bondYieldCurveBuilder.

Configuration example

bonds = array(ANY, 5)
for (i in 0..4) {
    bond_template = {
        "productType": "Cash",
        "assetType": "Bond",
        "bondType": "FixedRateBond",
        "instrumentId": "88" + lpad(string(i), 4, "0") + ".IB",
        "start": 2024.06.01,
        "maturity": 2024.06.01 + (i + 1) * 365,
        "issuePrice": 100,
        "coupon": 0.02,
        "dayCountConvention": "Actual365",
        "frequency": "Annual"
    };
    bonds[i] = parseInstrument(bond_template);
}

config = {
    "name": "CNY_TREASURY_BOND",
    "type": "BondYieldCurve",
    "bonds": bonds,
    "currency": "CNY",
    "dayCountConvention": "Actual365"
}

Description:

Build a bond yield curve with the curve name "CNY_TREASURY_BOND". Five randomly generated bonds (Instrument data) are used as reference instruments. The usage of other parameters can be found in the bondYieldCurveBuilder function.

During the build process, the engine calculates the remaining time to maturity for each bond based on the reference instrument information and the referenceDate specified in the engine parameters, and then reorders the bonds by maturity.

Data insertion schema

Column Name Data Type Description
type STRING Must be "Bond"
name STRING Bond name
price DOUBLE The market quotes

Data insertion example

typeCol = ["Bond", "Bond", "Bond", "Bond", "Bond"]
nameCol = ["880000.IB", "880001.IB", "880002.IB", "880003.IB", "880004.IB"]
priceCol = [0.015, 0.016, 0.017, 0.018, 0.019]  // YTM

data = table(typeCol as type, nameCol as name, priceCol as price)

Complete example

try{dropStreamEngine("MKTDATA_ENGINE")}catch(ex){}
referenceDate = 2025.01.01
bonds = array(ANY, 5)
for (i in 0..4) {
    bond_template = {
        "productType": "Cash",
        "assetType": "Bond",
        "bondType": "FixedRateBond",
        "instrumentId": "88" + lpad(string(i), 4, "0") + ".IB",
        "start": 2024.06.01,
        "maturity": 2024.06.01 + (i + 1) * 365,
        "issuePrice": 100,
        "coupon": 0.02,
        "dayCountConvention": "Actual365",
        "frequency": "Annual"
    };
    bonds[i] = parseInstrument(bond_template);
}

config = {
    "name": "CNY_TREASURY_BOND",
    "type": "BondYieldCurve",
    "bonds": bonds,
    "currency": "CNY",
    "dayCountConvention": "Actual365"
}

engine = createMktDataEngine("MKTDATA_ENGINE", referenceDate, [config])

typeCol = ["Bond", "Bond", "Bond", "Bond", "Bond"]
nameCol = ["880000.IB", "880001.IB", "880002.IB", "880003.IB", "880004.IB"]
priceCol = [0.015, 0.016, 0.017, 0.018, 0.019]  // YTM

data = table(typeCol as type, nameCol as name, priceCol as price)
engine.append!(data)
sleep(100)

re = getMktData(engine, "Curve", referenceDate, "CNY_TREASURY_BOND")
print(re)

Single-Currency Interest Rate Swap Curve

The mktDataConfig fields required for generating a single-currency interest rate swap curve include the following:

  • name: Required, the curve name
  • type: Required, must be "IrSingleCurrencyCurve"
  • insts: Required, an Any Vector, each element is a tuple consisting of three fields: [instName, instType, term]. Among them, instName and instType are STRING scalars, and term is either a STRING or a DURATION scalar.
  • currency: Required, the currency in which the curve is defined
  • dayCountConvention: Required, the day count convention to use
  • discountCurve: Optional, the discount curve
  • compounding: Optional, the compounding interest
  • frequency: Optional, the interest payment frequency

Except for insts, all other fields follow the same requirements as the parameters of irSingleCurrencyCurveBuilder.

Configuration example

config = {
    "name": "CNY_FR_007",
    "type": "IrSingleCurrencyCurve",
    "insts": [
        ["FR_007", "Deposit", 7d],
        ["CNY_FR_007", "IrVanillaSwap", 1M],
        ["CNY_FR_007", "IrVanillaSwap", 3M],
        ["CNY_FR_007", "IrVanillaSwap", 6M],
        ["CNY_FR_007", "IrVanillaSwap", 9M],
        ["CNY_FR_007", "IrVanillaSwap", 1y],
        ["CNY_FR_007", "IrVanillaSwap", 2y],
        ["CNY_FR_007", "IrVanillaSwap", 3y],
        ["CNY_FR_007", "IrVanillaSwap", 4y],
        ["CNY_FR_007", "IrVanillaSwap", 5y],
        ["CNY_FR_007", "IrVanillaSwap", 7y],
        ["CNY_FR_007", "IrVanillaSwap", 10y]
    ],
    "currency": "CNY",
    "dayCountConvention": "Actual365"
}

Note:This example builds a single-currency interest rate curve named CNY_FR_007, using the same set of market quotes as in Example 2 of irSingleCurrencyCurveBuilder.

Data insertion schema

Column Name Data Type Description
type STRING Currently,only "Deposit" or "IrVanillaSwap" is supported.
name STRING Instrument name
term STRING/DURATION The remaining maturity, e.g., "1M"
price DOUBLE The market quotes

Data insertion example

typeCol = [
    "Deposit", "IrVanillaSwap", "IrVanillaSwap", "IrVanillaSwap",
    "IrVanillaSwap", "IrVanillaSwap", "IrVanillaSwap", "IrVanillaSwap",
    "IrVanillaSwap", "IrVanillaSwap", "IrVanillaSwap", "IrVanillaSwap"
]

nameCol = [
    "FR_007", "CNY_FR_007", "CNY_FR_007", "CNY_FR_007",
    "CNY_FR_007", "CNY_FR_007", "CNY_FR_007", "CNY_FR_007",
    "CNY_FR_007", "CNY_FR_007", "CNY_FR_007", "CNY_FR_007"
]

termCol = [
    7d, 1M, 3M, 6M,
    9M, 1y, 2y, 3y,
    4y, 5y, 7y, 10y
]

priceCol = [
    2.3500, 2.3396, 2.3125, 2.3613,
    2.4075, 2.4513, 2.5750, 2.6763,
    2.7650, 2.8463, 2.9841, 3.1350
] \ 100

data = table(typeCol as type, nameCol as name, termCol as term, priceCol as price)

Complete example

try{dropStreamEngine("MKTDATA_ENGINE")}catch(ex){}
referenceDate = 2021.05.26

config = {
    "name": "CNY_FR_007",
    "type": "IrSingleCurrencyCurve",
    "insts": [
        ["FR_007", "Deposit", 7d],
        ["CNY_FR_007", "IrVanillaSwap", 1M],
        ["CNY_FR_007", "IrVanillaSwap", 3M],
        ["CNY_FR_007", "IrVanillaSwap", 6M],
        ["CNY_FR_007", "IrVanillaSwap", 9M],
        ["CNY_FR_007", "IrVanillaSwap", 1y],
        ["CNY_FR_007", "IrVanillaSwap", 2y],
        ["CNY_FR_007", "IrVanillaSwap", 3y],
        ["CNY_FR_007", "IrVanillaSwap", 4y],
        ["CNY_FR_007", "IrVanillaSwap", 5y],
        ["CNY_FR_007", "IrVanillaSwap", 7y],
        ["CNY_FR_007", "IrVanillaSwap", 10y]
    ],
    "currency": "CNY",
    "dayCountConvention": "Actual365"
}

engine = createMktDataEngine("MKTDATA_ENGINE", referenceDate, [config])

typeCol = [
    "Deposit", "IrVanillaSwap", "IrVanillaSwap", "IrVanillaSwap",
    "IrVanillaSwap", "IrVanillaSwap", "IrVanillaSwap", "IrVanillaSwap",
    "IrVanillaSwap", "IrVanillaSwap", "IrVanillaSwap", "IrVanillaSwap"
]

nameCol = [
    "FR_007", "CNY_FR_007", "CNY_FR_007", "CNY_FR_007",
    "CNY_FR_007", "CNY_FR_007", "CNY_FR_007", "CNY_FR_007",
    "CNY_FR_007", "CNY_FR_007", "CNY_FR_007", "CNY_FR_007"
]

termCol = [
    7d, 1M, 3M, 6M,
    9M, 1y, 2y, 3y,
    4y, 5y, 7y, 10y
]

priceCol = [
    2.3500, 2.3396, 2.3125, 2.3613,
    2.4075, 2.4513, 2.5750, 2.6763,
    2.7650, 2.8463, 2.9841, 3.1350
] \ 100

data = table(typeCol as type, nameCol as name, termCol as term, priceCol as price)

engine.append!(data)
sleep(100)

re = getMktData(engine, "Curve", referenceDate, "CNY_FR_007")
print(re)

Cross-Currency Interest Rate Swap Yield Curve

The mktDataConfig fields required for generating a cross-currency interest rate swap yield curve include the following:

  • name: Required, the curve name
  • type: Required, must be "IrCrossCurrencyCurve"
  • insts: Required, an Any Vector, each element is a tuple consisting of three fields: [instName, instType, term]. Among them, instName and instType are STRING scalars, and term is either a STRING or a DURATION scalar.
  • currency: Required, the currency in which the curve is defined
  • currencyPair: Required, current pair
  • dayCountConvention: Required, the day count convention to use
  • discountCurve: Required, the discount curve
  • compounding: Optional, the compounding interest
  • frequency: Optional, the interest payment frequency

Except for insts, all other fields follow the same requirements as the parameters of irCrossCurrencyCurveBuilder.

Configuration example

config = {
    "name": "USD_USDCNY_FX",
    "type": "IrCrossCurrencyCurve",
    "insts": [
        ("USDCNY", "FxSwap", "1d"),
        ("USDCNY", "FxSwap", "1w"),
        ("USDCNY", "FxSwap", "2w"),
        ("USDCNY", "FxSwap", "3w"),
        ("USDCNY", "FxSwap", "1M"),
        ("USDCNY", "FxSwap", "2M"),
        ("USDCNY", "FxSwap", "3M"),
        ("USDCNY", "FxSwap", "6M"),
        ("USDCNY", "FxSwap", "9M"),
        ("USDCNY", "FxSwap", "1y"),
        ("USDCNY", "FxSwap", "18M"),
        ("USDCNY", "FxSwap", "2y"),
        ("USDCNY", "FxSwap", "3y")
    ],
    "currency": "USD",
    "currencyPair": "USDCNY",
    "dayCountConvention": "Actual365",
    "discountCurve": "CNY_SHIBOR_3M"
}

Description:

In this example, the construction target is a cross-currency interest rate swap yield curve named "USD_USDCNY_FX".

The foreign exchange swap is used for pricing, and the discounting curve specified for the construction is "CNY_SHIBOR_3M".

Since the cross-currency interest rate swap yield curve already contains the currency pair information, there is no need to additionally define a foreign exchange spot rate as the construction target.

For detailed parameter requirements, please refer to irCrossCurrencyCurveBuilder.

Data insertion schema

Column Name Data Type Description
type STRING currently, only “FxSwap” is supported
name STRING FxSwap: the currency
term STRING / DURATION The remaining maturity, e.g., "1M"
price DOUBLE The market quotes

Data insertion example

typeCol = [
    "FxSwap", "FxSwap", "FxSwap", "FxSwap",
    "FxSwap", "FxSwap", "FxSwap", "FxSwap",
    "FxSwap", "FxSwap", "FxSwap", "FxSwap",
    "FxSwap"
]
nameCol = [
    "USDCNY", "USDCNY", "USDCNY", "USDCNY",
    "USDCNY", "USDCNY", "USDCNY", "USDCNY",
    "USDCNY", "USDCNY", "USDCNY", "USDCNY",
    "USDCNY"
]
termCol = [
    "1d", "1w", "2w", "3w",
    "1M", "2M", "3M", "6M",
    "9M", "1y", "18M", "2y",
    "3y"
]
priceCol = [
    -5.54, -39.00, -75.40, -113.20,
    -177.00, -317.00, -466.00, -898.50,
    -1284.99, -1676.00, -2320.00, -2870.00,
    -3962.50
] \ 10000

data = table(typeCol as type, nameCol as name, termCol as term, priceCol as price)
insert into data values("FxSpot", "USDCNY", "0d", 7.1627)

Complete example

In this example, the USD implied yield curve (USD_USDCNY_FX) is automatically constructed using the market data engine from USDCNY FX swap quotes and the CNY_FR_007 curve.

try{dropStreamEngine("MKTDATA_ENGINE")}catch(ex){}
referenceDate = 2025.08.18

config = {
    "name": "USD_USDCNY_FX",
    "type": "IrCrossCurrencyCurve",
    "insts": [
        ("USDCNY", "FxSwap", "1d"),
        ("USDCNY", "FxSwap", "1w"),
        ("USDCNY", "FxSwap", "2w"),
        ("USDCNY", "FxSwap", "3w"),
        ("USDCNY", "FxSwap", "1M"),
        ("USDCNY", "FxSwap", "2M"),
        ("USDCNY", "FxSwap", "3M"),
        ("USDCNY", "FxSwap", "6M"),
        ("USDCNY", "FxSwap", "9M"),
        ("USDCNY", "FxSwap", "1y"),
        ("USDCNY", "FxSwap", "18M"),
        ("USDCNY", "FxSwap", "2y"),
        ("USDCNY", "FxSwap", "3y")
    ],
    "currency": "USD",
    "currencyPair": "USDCNY",
    "dayCountConvention": "Actual365",
    "discountCurve": "CNY_SHIBOR_3M"
}


typeCol = [
    "FxSwap", "FxSwap", "FxSwap", "FxSwap",
    "FxSwap", "FxSwap", "FxSwap", "FxSwap",
    "FxSwap", "FxSwap", "FxSwap", "FxSwap",
    "FxSwap"
]
nameCol = [
    "USDCNY", "USDCNY", "USDCNY", "USDCNY",
    "USDCNY", "USDCNY", "USDCNY", "USDCNY",
    "USDCNY", "USDCNY", "USDCNY", "USDCNY",
    "USDCNY"
]
termCol = [
    "1d", "1w", "2w", "3w",
    "1M", "2M", "3M", "6M",
    "9M", "1y", "18M", "2y",
    "3y"
]
priceCol = [
    -5.54, -39.00, -75.40, -113.20,
    -177.00, -317.00, -466.00, -898.50,
    -1284.99, -1676.00, -2320.00, -2870.00,
    -3962.50
] \ 10000

data = table(typeCol as type, nameCol as name, termCol as term, priceCol as price)
insert into data values("FxSpot", "USDCNY", "0d", 7.1627)


cnyShibor3mDict = {
    "mktDataType": "Curve",
    "curveType": "IrYieldCurve",
    "curveName": "CNY_SHIBOR_3M",
    "referenceDate": referenceDate,
    "currency": "CNY",
    "dayCountConvention": "Actual365",
    "compounding": "Continuous",
    "interpMethod": "Linear",
    "extrapMethod": "Flat",
    "dates": [
        2025.08.21, 2025.08.27, 2025.09.03, 2025.09.10,
        2025.09.22, 2025.10.20, 2025.11.20, 2026.02.20,
        2026.05.20, 2026.08.20, 2027.02.22, 2027.08.20,
        2028.08.21
    ],
    "values": [
        1.5113, 1.5402, 1.5660, 1.5574,
        1.5556, 1.5655, 1.5703, 1.5934,
        1.6040, 1.6020, 1.5928, 1.5842,
        1.6068
    ] \ 100
}

cnyShibor3m = parseMktData(cnyShibor3mDict)

engine = createMktDataEngine("MKTDATA_ENGINE", referenceDate, [config], historicalData=[cnyShibor3m])

engine.append!(data)
sleep(100)

re = getMktData(engine, "Curve", referenceDate, "USD_USDCNY_FX")
print(re)
  1. Since the construction target automatically includes foreign exchange spot rate, the input data must also contain the corresponding quotation data; otherwise, the construction will fail.
  2. In this example, CNY_SHIBOR_3M is provided to the engine as historical data rather than being built in real time, so the corresponding curve needs to be prepared in advance.

Foreign Exchange Volatility Surface

The mktDataConfig fields required for generating a foreign exchange volatility surface include the following:

  • name: Required, the surface name
  • type: Required, must be "FxVolatilitySurface"
  • names: Required, the names of market volatility quotes,which must be a permutation of ["ATM", "D25_RR", "D25_BF", "D10_RR", "D10_BF"]
  • terms: Required, the tenors associated with market quotes
  • currencyPair: Required, current pair
  • discountCurve: Required, the discount curve
  • foreignCurve: Required, the foreign discount curve
  • mode: Required, the model used to construct the surface

All fields follow the same requirements as the parameters of fxVolatilitySurfaceBuilder.

Configuration example

config = {
    "name": "USDCNY",
    "type": "FxVolatilitySurface",
    "names": ["ATM", "D25_RR", "D25_BF", "D10_RR", "D10_BF"],
    "terms": ["1d", "1w", "2w", "3w", "1M", "2M", "3M", "6M", "9M", "1y", "18M", "2y", "3y"],
    "currencyPair": "USDCNY",
    "domesticCurve": "CNY_FR_007",
    "foreignCurve": "USD_USDCNY_FX",
    "model": "SVI"
}

Description

In this example, the construction target is a foreign exchange volatility surface named USDCNY.

The discounting curve CNY_FR_007 is used for the domestic currency, USD_USDCNY_FX is used for the foreign currency, and the SVI model is applied to build the volatility surface.

Data insertion schema

Column Name Data Type Description
type STRING Must be FxOption
name STRING Currency pair
subType STRING “ATM” / “D25_RR” / “D25_BF” / “D10_RR” / “D10_BF”
term STRING / DURATION The remaining maturity, e.g., "1M"
price DOUBLE The market quotes

Data insertion example

typeCol = take("FxOption", 65)
nameCol = take("USDCNY", 65)
subTypeCol = take(["ATM"], 13)
    .append!(take(["D25_RR"], 13))
    .append!(take(["D25_BF"], 13))
    .append!(take(["D10_RR"], 13))
    .append!(take(["D10_BF"], 13))
termCol = take([
    "1d", "1w", "2w", "3w", "1M", "2M", "3M", "6M", "9M", "1y", "18M", "2y", "3y"
], 65)
priceCol = [
    0.030000, -0.007500, 0.003500, -0.010000, 0.005500, 
    0.020833, -0.004500, 0.002000, -0.006000, 0.003800, 
    0.022000, -0.003500, 0.002000, -0.004500, 0.004100, 
    0.022350, -0.003500, 0.002000, -0.004500, 0.004150, 
    0.024178, -0.003000, 0.002200, -0.004750, 0.005500, 
    0.027484, -0.002650, 0.002220, -0.004000, 0.005650, 
    0.030479, -0.002500, 0.002400, -0.003500, 0.005750, 
    0.035752, -0.000500, 0.002750,  0.000000, 0.006950, 
    0.038108,  0.001000, 0.002800,  0.003000, 0.007550, 
    0.039492,  0.002250, 0.002950,  0.005000, 0.007550, 
    0.040500,  0.004000, 0.003100,  0.007000, 0.007850, 
    0.041750,  0.005250, 0.003350,  0.008000, 0.008400, 
    0.044750,  0.006250, 0.003400,  0.009000, 0.008550
].reshape(5:13).transpose().flatten()

data = table(typeCol as type, nameCol as name, subTypeCol as subType, termCol as term, priceCol as price)
insert into data values("FxSpot", "USDCNY", "", "0d", 7.1627)

Complete example

This example demonstrates how to use DolphinDB’s market data engine (createMktDataEngine) to build and manage a USDCNY FX volatility surface. The process includes the following steps:

  1. Prepare volatility quotes, spot exchange rates, and yield curve data.
  2. Use parseMktData to convert curve data provided in dictionary format into MKTDATA objects.
  3. Create a market data engine named "MKTDATA_ENGINE" and configure the construction parameters for the USDCNY volatility surface using the SVI model. The historical curves CNY_FR_007 and USD_USDCNY_FX are then loaded into the engine.
  4. Retrieve the constructed USDCNY FX volatility surface from the engine using getMktData, which can be used for subsequent FX option pricing.
try{dropStreamEngine("MKTDATA_ENGINE")}catch(ex){}
referenceDate = 2025.08.18

config = {
    "name": "USDCNY",
    "type": "FxVolatilitySurface",
    "names": ["ATM", "D25_RR", "D25_BF", "D10_RR", "D10_BF"],
    "terms": ["1d", "1w", "2w", "3w", "1M", "2M", "3M", "6M", "9M", "1y", "18M", "2y", "3y"],
    "currencyPair": "USDCNY",
    "domesticCurve": "CNY_FR_007",
    "foreignCurve": "USD_USDCNY_FX",
    "model": "SVI"
}

typeCol = take("FxOption", 65)
nameCol = take("USDCNY", 65)
subTypeCol = take(["ATM"], 13)
    .append!(take(["D25_RR"], 13))
    .append!(take(["D25_BF"], 13))
    .append!(take(["D10_RR"], 13))
    .append!(take(["D10_BF"], 13))
termCol = take([
    "1d", "1w", "2w", "3w", "1M", "2M", "3M", "6M", "9M", "1y", "18M", "2y", "3y"
], 65)
priceCol = [
    0.030000, -0.007500, 0.003500, -0.010000, 0.005500, 
    0.020833, -0.004500, 0.002000, -0.006000, 0.003800, 
    0.022000, -0.003500, 0.002000, -0.004500, 0.004100, 
    0.022350, -0.003500, 0.002000, -0.004500, 0.004150, 
    0.024178, -0.003000, 0.002200, -0.004750, 0.005500, 
    0.027484, -0.002650, 0.002220, -0.004000, 0.005650, 
    0.030479, -0.002500, 0.002400, -0.003500, 0.005750, 
    0.035752, -0.000500, 0.002750,  0.000000, 0.006950, 
    0.038108,  0.001000, 0.002800,  0.003000, 0.007550, 
    0.039492,  0.002250, 0.002950,  0.005000, 0.007550, 
    0.040500,  0.004000, 0.003100,  0.007000, 0.007850, 
    0.041750,  0.005250, 0.003350,  0.008000, 0.008400, 
    0.044750,  0.006250, 0.003400,  0.009000, 0.008550
].reshape(5:13).transpose().flatten()

data = table(typeCol as type, nameCol as name, subTypeCol as subType, termCol as term, priceCol as price)
insert into data values("FxSpot", "USDCNY", "", "0d", 7.1627)

domesticCurveDict = {
    "mktDataType": "Curve",
    "curveName": "CNY_FR_007",
    "curveType": "IrYieldCurve",
    "referenceDate": referenceDate,
    "currency": "CNY",
    "dayCountConvention": "Actual365",
    "compounding": "Continuous",  
    "interpMethod": "Linear",
    "extrapMethod": "Flat",
    "frequency": "Annual",
    "dates": [
        2025.08.21, 2025.08.27, 2025.09.03, 2025.09.10, 2025.09.22,
        2025.10.20, 2025.11.20, 2026.02.24, 2026.05.20, 2026.08.20,
        2027.02.22, 2027.08.20, 2028.08.21
    ],
    "values": [
        1.5113, 1.5402, 1.5660, 1.5574, 1.5556,
        1.5655, 1.5703, 1.5934, 1.6040, 1.6020, 
        1.5928, 1.5842, 1.6068
    ] \ 100
}
domesticCurve = parseMktData(domesticCurveDict)

foreignCurveDict = {
    "mktDataType": "Curve",
    "curveName": "USD_USDCNY_FX",
    "curveType": "IrYieldCurve",
    "referenceDate": referenceDate,
    "currency": "USD",
    "dayCountConvention": "Actual365",
    "compounding": "Continuous",  
    "interpMethod": "Linear",
    "extrapMethod": "Flat",
    "frequency": "Annual",
    "dates": [
        2025.08.21, 2025.08.27, 2025.09.03, 2025.09.10, 2025.09.22,
        2025.10.20, 2025.11.20, 2026.02.24, 2026.05.20, 2026.08.20,
        2027.02.22, 2027.08.20, 2028.08.21
    ],
    "values": [
        4.3345, 4.3801, 4.3119, 4.3065, 4.2922, 
        4.2196, 4.1599, 4.0443, 4.0244, 3.9698, 
        3.7740, 3.6289, 3.5003
    ] \ 100
}
foreignCurve = parseMktData(foreignCurveDict)

engine = createMktDataEngine("MKTDATA_ENGINE", referenceDate, [config], historicalData=[domesticCurve, foreignCurve])

engine.append!(data)
sleep(100)

re = getMktData(engine, "Surface", referenceDate, "USDCNY")
print(re)
  1. Since the construction target automatically includes a foreign exchange spot rate curve, the input data must also contain the corresponding quotation data; otherwise, the construction will fail.
  2. In this example, CNY_FR_007 and USD_USDCNY_FX are provided to the engine as historical data rather than being built in real time, so the corresponding curves need to be prepared in advance.

Example of the handler parameter

Specify a custom function

Taking the construction of a foreign exchange spot rate curve as an example, define a custom function to print the generated market data.

def myHandler(kind, date, name, data) {
    print(data)
}

try{dropStreamEngine("MKTDATA_ENGINE")}catch(ex){}
referenceDate = 2025.01.01

config1 = {
    "name": "USDCNY",
    "type": "FxSpotRate"
}
config2 = {
    "name": "EURUSD",
    "type": "FxSpotRate"
}
config3 = {
    "name": "EURCNY",
    "type": "FxSpotRate"
}

engine = createMktDataEngine("MKTDATA_ENGINE", referenceDate, [config1, config2, config3], handler=myHandler)

typeCol = ["FxSpot", "FxSpot", "FxSpot"]
nameCol = ["USDCNY", "EURCNY", "EURUSD"]
priceCol = [7.12, 7.88, 1.10]

data = table(typeCol as type, nameCol as name, priceCol as price)

engine.append!(data)
sleep(100)

Specify as a shared memory table

Define a shared table with the following schema (the column order must be consistent).

Column Name Data Type
kind STRING
date DATE
name STRING
data MKTDATA

Complete example

share streamTable(1:0, `kind`date`name`data, [STRING, DATE, STRING, MKTDATA]) as st

try{dropStreamEngine("MKTDATA_ENGINE")}catch(ex){}
referenceDate = 2025.01.01

config1 = {
    "name": "USDCNY",
    "type": "FxSpotRate"
}
config2 = {
    "name": "EURUSD",
    "type": "FxSpotRate"
}
config3 = {
    "name": "EURCNY",
    "type": "FxSpotRate"
}

engine = createMktDataEngine("MKTDATA_ENGINE", referenceDate, [config1, config2, config3], handler=st)

typeCol = ["FxSpot", "FxSpot", "FxSpot"]
nameCol = ["USDCNY", "EURCNY", "EURUSD"]
priceCol = [7.12, 7.88, 1.10]

data = table(typeCol as type, nameCol as name, priceCol as price)

engine.append!(data)
sleep(100)

print(select * from st)

Specify as a pricing engine

Create a pricing engine and pass it as the handler parameter.

Complete example

try{dropStreamEngine("MKTDATA_ENGINE")}catch(ex){}
try{dropStreamEngine("PRICING_ENGINE")}catch(ex){}
referenceDate = 2025.01.01

bonds = array(ANY, 5)
for (i in 0..4) {
    bond_template = {
        "productType": "Cash",
        "assetType": "Bond",
        "bondType": "FixedRateBond",
        "instrumentId": "88" + lpad(string(i), 4, "0") + ".IB",
        "start": 2024.06.01,
        "maturity": 2024.06.01 + (i + 1) * 365,
        "issuePrice": 100,
        "coupon": 0.02,
        "dayCountConvention": "Actual365",
        "frequency": "Annual"
    };
    bonds[i] = parseInstrument(bond_template);
}

config = {
    "name": "CNY_TREASURY_BOND",
    "type": "BondYieldCurve",
    "bonds": bonds,
    "currency": "CNY",
    "dayCountConvention": "Actual365"
}

bondDict = {
    "productType": "Cash",
    "assetType": "Bond",
    "bondType": "FixedRateBond",
    "instrumentId": "880010.IB",
    "start": 2024.05.01,
    "maturity": 2028.05.01,
    "issuePrice": 100,
    "coupon": 0.02,
    "dayCountConvention": "Actual365",
    "frequency": "Annual",
    "discountCurve": "CNY_FR_007"
}
bond = parseInstrument(bondDict)

share streamTable(1:0, `name`date`price, [STRING, DATE, DOUBLE]) as priceSt

pricingEngine = createPricingEngine("PRICING_ENGINE", [bond], tableInsert{priceSt})

mktdataEngine = createMktDataEngine("MKTDATA_ENGINE", referenceDate, [config], handler=pricingEngine)

typeCol = ["Bond", "Bond", "Bond", "Bond", "Bond"]
nameCol = ["880000.IB", "880001.IB", "880002.IB", "880003.IB", "880004.IB"]
priceCol = [0.015, 0.016, 0.017, 0.018, 0.019]  // YTM

data = table(typeCol as type, nameCol as name, priceCol as price)

mktdataEngine.append!(data)
sleep(100)

re = getMktData(mktdataEngine, "Curve", referenceDate, "CNY_FR_007")
print(re)

print(select * from priceSt)

In this example, bonds 880000.IB to 880004.IB are used as benchmark bonds to build the curve CNY_TREASURY_BOND, which is then provided as an input curve to the price engine to price 880010.IB .

Finally, the pricing results are written to the priceSt table.

Related functions: appendMktData, append!, getMktData, createPricingEngine