Market Data

GF API Documentation

We'll need some data to make trading decisions. GF API can give us quotes, DOMs, bars, ticks and histograms. To do so, we will request a subscription or a chunk of data, and listen to the response event.

This topic contains the following sections:

Quotes

Quotes are the simplest kind of market data. Let's enhance our example to output all quotes for a symbol retrieved by symbol lookup.

Subscribe to Quotes
private static SymbolLookupRequestID _esh18SymbolLookupRequestID;
private static IPriceSubscription _quoteSubscription;

private static void RegisterOnPriceTick(IGFClient client)
{
    client.Subscriptions.Price.PriceTick += GFClient_OnPriceTick;
}

private static void GFClient_OnSymbolLookupReceived(IGFClient client, GF.Api.Contracts.Lookup.SymbolLookupEventArgs e)
{
    if (e.RequestID == _esh18SymbolLookupRequestID)
    {
        Console.WriteLine($"Symbol lookup request for ESH18 found {e.Contracts.Count} contracts");
        foreach (var contract in e.Contracts)
        {
            DisplayContract(contract);
            _quoteSubscription = client.Subscriptions.Price.Subscribe(contract.ID);
        }
    }
}

private static void GFClient_OnPriceTick(IGFClient client, GF.Api.Contracts.PriceChangedEventArgs e)
{
    Console.WriteLine(
        "{0} {1} O:{2} H:{3} L:{4} Last:{5}, Bid:{6} Ask:{7} TotalVol:{8}",
        e.Contract.Symbol,
        e.Price.LastDateTime,
        e.Contract.PriceToString(e.Price.OpenPrice),
        e.Contract.PriceToString(e.Price.HighPrice),
        e.Contract.PriceToString(e.Price.LowPrice),
        e.Contract.PriceToString(e.Price.LastPrice),
        e.Contract.PriceToString(e.Price.BidPrice),
        e.Contract.PriceToString(e.Price.AskPrice),
        e.Price.TotalVol);
}

private static void UnsubscribeAll()
{
    _quoteSubscription.Unsubscribe();
}
Tip Tip

Alternatively, we could access the price from IContract.CurrentPrice.

To unsubscribe, call ISubscription.Unsubscribe. Subscriptions are counted, so you must Unsubscribe from every ISubscription to avoid subscription leaks. There are a limited number of simultaneous subscriptions allowed.

Note Note

To have accurate position values, the relevant contracts need to have quote subscriptions. In legacy OEC API, the API did this automatically, but in GF API it is the client's responsibility. This allows more control over the limited number of active subscriptions.

For additional guidance, see the PNL Subscription Manager snippet.

DOM

DOM subscription is similar to Quotes:

Subscribe to DOM
private static IDomSubscription _domSubscription;

private static void RegisterOnDOMChanged(IGFClient client)
{
    client.Subscriptions.Dom.DomChanged += GFClient_OnDomChanged;
}

private static void GFClient_OnSymbolLookupReceived(IGFClient client, GF.Api.Contracts.Lookup.SymbolLookupEventArgs e)
{
    _domSubscription = client.Subscriptions.Dom.Subscribe(e.Contracts.First().ID);
}

private static void GFClient_OnDomChanged(IGFClient client, GF.Api.Subscriptions.Doms.DomChangedEventArgs e)
{
    GF.Api.Subscriptions.Doms.IDom dom = e.Contract.DOM;
    Console.WriteLine(
        "DOM {0} {1} Bids: {2} Asks: {3} Best Bid: {4} Best Ask: {5}",
        e.Contract.Symbol,
        dom.LastUpdate,
        dom.BidLevels.Count,
        dom.AskLevels.Count,
        dom.BidLevels.Count > 0 ? dom.BidSizes[0] + "@" + e.Contract.PriceToString(dom.BidLevels[0]) : "-",
        dom.AskLevels.Count > 0 ? dom.AskSizes[0] + "@" + e.Contract.PriceToString(dom.AskLevels[0]) : "-");
}

private static void UnsubscribeAll()
{
    _domSubscription.Unsubscribe();
}
Bars

For bars, we can either request a single chunk of historical data, or load some historical bars up to now and open a stream of updates via subscription.

GF API provides a variety of bar types:

  • Second
  • Minute
  • Range
  • Momentum
  • Tick
  • Volume
  • Daily
  • Weekly
  • Monthly

You can use IBarDurationFactory and IBarDescriptionFactory to help construct the subscription parameters.

Subscribe to Bars
private static void RegisterOnBarsReceived(IGFClient client)
{
    client.Subscriptions.Bars.BarsReceived += GFClient_OnBarsReceived;
}

private static void GFClient_OnSymbolLookupReceived(IGFClient client, GF.Api.Contracts.Lookup.SymbolLookupEventArgs e)
{
    // Subscribe 10-min bars and loads previous 3 days of historical bars
    client.Subscriptions.Bars.Subscribe(
        e.Contracts.First().ID,
        client.Subscriptions.Bars.Duration.Create(DateTime.UtcNow.AddDays(-3)),
        client.Subscriptions.Bars.Description.CreateMinutes(10));
}

private static void GFClient_OnBarsReceived(IGFClient client, GF.Api.Subscriptions.Bars.BarsReceivedEventArgs e)
{
    Console.WriteLine($"{e.Bars.Count} bars received for {e.Subscription.Contract.Symbol} {e.Subscription.Description.Type} {e.Subscription.Description.Interval}");
    foreach (var bar in e.Bars)
        DisplayBar(e.Subscription.Contract, bar);
}

private static void DisplayBar(GF.Api.Contracts.IContract contract, Bar bar)
{
    Console.WriteLine(
        "{0} {1} O:{2} H:{3} L:{4} C:{5} Vol:{6} Ticks:{7} UpVol:{8} DownVol:{9}",
        contract.Symbol,
        bar.OpenTimestamp.ToLocalTime(),
        contract.PriceToString(bar.Open),
        contract.PriceToString(bar.High),
        contract.PriceToString(bar.Low),
        contract.PriceToString(bar.Close),
        bar.Volume,
        bar.Ticks,
        bar.UpVolume,
        bar.DownVolume);
}
Ticks

Ticks are similar to Bars:

Subscribe to Ticks
private static void RegisterOnTicksReceived(IGFClient client)
{
    client.Subscriptions.Ticks.TicksReceived += GFClient_OnTicksReceived;
}

private static void GFClient_OnSymbolLookupReceived(IGFClient client, GF.Api.Contracts.Lookup.SymbolLookupEventArgs e)
{
    // Subscribe 10-min bars and loads previous 3 days of historical bars
    client.Subscriptions.Bars.Subscribe(
        e.Contracts.First().ID,
        client.Subscriptions.Bars.Duration.Create(DateTime.UtcNow.AddDays(-3)),
        client.Subscriptions.Bars.Description.CreateMinutes(10));

    // Request ticks for the last hour without further updates
    client.Subscriptions.Ticks.Subscribe(
        e.Contracts.First().ID,
        client.Subscriptions.Ticks.Duration.Create(DateTime.UtcNow.AddHours(-3), DateTime.UtcNow));
}

private static void GFClient_OnTicksReceived(IGFClient client, GF.Api.Subscriptions.Ticks.TicksReceivedEventArgs e)
{
    Console.WriteLine($"{e.Ticks.Count} ticks received for {e.Subscription.Contract.Symbol}");
    foreach (var tick in e.Ticks)
    {
        Console.WriteLine($"{tick.Timestamp.ToLocalTime()} {tick.Volume}@{tick.Price}\tBid:{tick.BidPrice} Ask:{tick.AskPrice}");
    }
}
Subscription Limits

Subscriptions are a limited resource in GF API. If you no longer need a subscription, unsubscribe from it. If the subscription limit is reached, additional subscriptions will be declined by the server.

Current subscription limits properties:

DOMs

Number of DOM subscriptions

MaxBars

Number of bar subscriptions

MaxTicks

Number of tick subscriptions

Quotes

Number of futures-related quote subscriptions

You can check the property values like so:

Get Property
private string GetBarLimit(IGFClient client)
{
    return client.Properties.ContainsKey("MaxBars")
        ? client.Properties["MaxBars"]
        : null;
}

Bar and tick requests are a more expensive resource than quotes and DOMs, so they have additional limitations. These limits may be changed at any time:

  • MaxBars = 8192: Maximum amount of bars returned to a client per request

  • MaxDayBarDays = 365: Maximum allowed days to load for day and day-based bars

  • MaxIntraBarDays = 90: Maximum allowed days to load for intraday bars

  • MaxPerGroup = 4096: Maximum items per collection returned to a client

  • MaxTickBasedBarDays = 10: Maximum allowed days to load for tick-based bars

  • MaxTickDays = 3: Maximum allowed days to load for ticks

  • MaxTicks = 65536: Maximum amount of ticks returned to a client per request

Let's output the current subscriptions status to the console window.

Check Subscription Limits
private static System.Timers.Timer _statusTimer;

private static void MonitorSubscriptionLimits(IGFClient client)
{
    _statusTimer = new System.Timers.Timer {Interval = TimeSpan.FromSeconds(1).TotalMilliseconds};
    _statusTimer.Elapsed += (_, __) => StatusTimer_Tick(client);
    _statusTimer.Start();

    Console.WriteLine("Press any key to exit");
    Console.ReadKey();
}

private static void StatusTimer_Tick(IGFClient client)
{
    client.Threading.BeginInvoke(() =>
    {
        if (client.Connection.Aggregate.IsConnected)
            ShowCurrentSubscriptionStatus(client);
    });
}

private static void ShowCurrentSubscriptionStatus(IGFClient client)
{
    Console.WriteLine(
        "Quotes: {0}/{1}; DOMs: {2}/{3}; bars: {4}/{5}; ticks: {6}/{7}",
        GetQuotesSubscriptionCount(client), GetSubscriptionLimit(client, "Quotes"),
        GetDomSubscriptionCount(client), GetSubscriptionLimit(client, "DOMs"),
        GetBarsSubscriptionCount(client), GetSubscriptionLimit(client, "MaxBars"),
        GetTicksSubscriptionCount(client), GetSubscriptionLimit(client, "MaxTicks"));
}

private static int GetSubscriptionLimit(IGFClient client, string key)
{
    var limit = 0;
    if (client.Properties.ContainsKey(key))
        int.TryParse(client.Properties[key], out limit);
    return limit;
}

private static IEnumerable<GF.Api.Subscriptions.ISubscription> GetContinuousSubscriptions(IGFClient client, params SubscriptionType[] subscriptionTypes)
{
    return client.Subscriptions.Get()
        .Where(subscription =>
            subscription.Duration.Continuity == GF.Api.Subscriptions.Continuity.Continuous
            && subscriptionTypes.Contains(subscription.Description.Type));
}

private static int GetQuotesSubscriptionCount(IGFClient client)
{
    return GetContinuousSubscriptions(client, SubscriptionType.Price).Count();
}

private static int GetDomSubscriptionCount(IGFClient client)
{
    return GetContinuousSubscriptions(client, SubscriptionType.DOM).Count();
}

private static int GetBarsSubscriptionCount(IGFClient client)
{
    return GetContinuousSubscriptions(
        client,
        SubscriptionType.Bar,
        SubscriptionType.DayBar,
        SubscriptionType.WeeklyBar,
        SubscriptionType.MonthlyBar,
        SubscriptionType.SecondBar,
        SubscriptionType.RangeBar,
        SubscriptionType.MomentumBar,
        SubscriptionType.TickBar,
        SubscriptionType.VolumeBar)
        .Count();
}

private static int GetTicksSubscriptionCount(IGFClient client)
{
    return GetContinuousSubscriptions(client, SubscriptionType.Tick, SubscriptionType.Histogram).Count();
}