-- Load the API modules used by the script local gs = require 'geneos.sampler' local md = require 'geneos.marketdata' gs.logMessage('INFO', "Starting") -- Process configuration parameters -- ================================ -- TODO -- Configure and connect to market data sources -- ============================================ -- Feed configuration is stored in a Lua table local feedConfiguration = {} -- Feed Controller configuration feedConfiguration.feed = { type = "example", ["library.filename"] = "flm-feed-example.so", } -- Feed adapter configuration feedConfiguration.example = { publishingPeriod = 200, } -- Define the set of instruments -- Instrument subscriptions are defined as a mapping from display name to stock code feedConfiguration.instruments = { GOOG = "DATA_SERVICE.GOOG", IBM = "DATA_SERVICE.IBM", } -- Define the set of fields -- Fields are defined as a mapping from display name to field code feedConfiguration.fields = { Bid = "01_BID", Trade = "02_TRADE_PRICE", Ask = "03_ASK", } -- Create and start a feed using the above config local tutorialFeed = assert(md.addFeed("Tutorial-Feed", feedConfiguration)) tutorialFeed:start() -- Define functions to analyse the data -- ==================================== -- Utility function to round non-nil (positive) values to two decimal places local function round2dp(value) return value and math.floor(value * 100 + 0.5) / 100 end -- A table to map instrument names to the last tick seen for each instrument local prevTick = {} -- A function to process the sample data for a specific instrument. -- Takes a single string argument; the instrument name. local function processTicks(instName) local tick = prevTick[instName] or { field = {} } tick.next = tutorialFeed:getTicks(instName) -- Extract required values from 'tick' local prevTime = tick.timeLast -- Metrics we will compute from the tick data local tickCount, maxInterval, minSpread, maxSpread tickCount = 0 -- Iterate over the ticks while tick.next do tick = tick.next -- Use tick data to calculate metrics tickCount = tickCount + 1 local interval = prevTime and tick.timeFirst - prevTime if not maxInterval or interval > maxInterval then maxInterval = interval end prevTime = tick.timeLast local spread = tick.field.Ask - tick.field.Bid if not minSpread or spread < minSpread then minSpread = spread end if not maxSpread or spread > maxSpread then maxSpread = spread end end prevTick[instName] = tick -- Create a table of row values. -- We will place this result directly into a view, so the field names must match the column names. local rowValues = { ticksPerSample = tickCount, maxInterval = round2dp(maxInterval), minSpread = round2dp(minSpread), maxSpread = round2dp(maxSpread), tradePrice = tick.field.Trade -- Trade price is taken from the last tick seen } -- Return two values; (1) a table of row values and (2) the count of new ticks return rowValues, tickCount end -- Create data view(s) -- =================== -- Define columns and create view local cols = { "instrument", "minSpread", "maxSpread", "ticksPerSample", "maxInterval", "tradePrice" } local view = assert(gs.createView("spreads", cols)) -- Publish initial view data view.headline.totalTicks = 0 assert(view:publish()) -- Define the doSample function which will be called every sample -- ============================================================== local totalTicks = 0 gs.doSample = function() for name, _ in pairs(feedConfiguration.instruments) do -- Loop over each subscribed instrument local rowResult, tickCount = processTicks(name) -- processTicks() returns 2 values view.row[name] = rowResult -- update view row for this instrument with new metrics totalTicks = totalTicks + tickCount -- update tally of total ticks observed end view.headline.totalTicks = totalTicks assert(view:publish()) end gs.logMessage('INFO', "Started OK") -- End of script