diff --git a/samples/CandleDataResponseReader/Program.cs b/samples/CandleDataResponseReader/Program.cs index 3153ed04..64457956 100644 --- a/samples/CandleDataResponseReader/Program.cs +++ b/samples/CandleDataResponseReader/Program.cs @@ -37,7 +37,6 @@ private static async Task Main(string[] args) // Create an HTTP client with the base URL and the authentication token using var client = CreateHttpClient("https://tools.dxfeed.com/", token); - var start = DateTimeOffset.Now.AddDays(-2).ToString("yyyyMMdd", InvariantCulture); var stop = DateTimeOffset.Now.AddDays(-1).ToString("yyyyMMdd", InvariantCulture); // URL for fetching candle events. @@ -130,6 +129,11 @@ private static List ParseEvents(HttpResponseMessage message) private static List ParseEvents(StreamReader reader) where T : ITimeSeriesEvent { + if (reader.EndOfStream) + { + return new List(); + } + var config = new CsvConfiguration(InvariantCulture) { AllowComments = false, HasHeaderRecord = true, MissingFieldFound = null, DetectDelimiter = true, diff --git a/src/DxFeed.Graal.Net/DxFeed.Graal.Net.csproj b/src/DxFeed.Graal.Net/DxFeed.Graal.Net.csproj index ad373f4a..94b6e42b 100644 --- a/src/DxFeed.Graal.Net/DxFeed.Graal.Net.csproj +++ b/src/DxFeed.Graal.Net/DxFeed.Graal.Net.csproj @@ -23,7 +23,11 @@ - + + + + + diff --git a/src/DxFeed.Graal.Net/Ipf/InstrumentProfile.cs b/src/DxFeed.Graal.Net/Ipf/InstrumentProfile.cs index ca22d877..d65d42f9 100644 --- a/src/DxFeed.Graal.Net/Ipf/InstrumentProfile.cs +++ b/src/DxFeed.Graal.Net/Ipf/InstrumentProfile.cs @@ -4,11 +4,10 @@ // If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // +using System.Collections.Generic; +using DxFeed.Graal.Net.Native.Ipf; using DxFeed.Graal.Net.Utils; -// Disable auto-property -#pragma warning disable S2292 - namespace DxFeed.Graal.Net.Ipf; /// @@ -18,44 +17,13 @@ namespace DxFeed.Graal.Net.Ipf; /// public class InstrumentProfile { - private string type = string.Empty; - private string symbol = string.Empty; - private string description = string.Empty; - private string localSymbol = string.Empty; - private string localDescription = string.Empty; - private string country = string.Empty; - private string opol = string.Empty; - private string exchangeData = string.Empty; - private string exchanges = string.Empty; - private string currency = string.Empty; - private string baseCurrency = string.Empty; - private string cfi = string.Empty; - private string isin = string.Empty; - private string sedol = string.Empty; - private string cusip = string.Empty; - private int icb; - private int sic; - private double multiplier; - private string product = string.Empty; - private string underlying = string.Empty; - private double spc; - private string additionalUnderlyings = string.Empty; - private string mmy = string.Empty; - private int expiration; - private int lastTrade; - private double strike; - private string optionType = string.Empty; - private string expirationStyle = string.Empty; - private string settlementStyle = string.Empty; - private string priceIncrements = string.Empty; - private string tradingHours = string.Empty; + private readonly InstrumentProfileHandle handle; /// /// Initializes a new instance of the class. /// - public InstrumentProfile() - { - } + public InstrumentProfile() => + handle = InstrumentProfileHandle.Create(); /// /// Initializes a new instance of the class, @@ -68,40 +36,11 @@ public InstrumentProfile() /// It performs a deep copy, ensuring that the new instance does not share references with the original, /// making it safe from modifications to the original instance. /// - public InstrumentProfile(InstrumentProfile ip) - { - type = ip.type; - symbol = ip.symbol; - description = ip.description; - localSymbol = ip.localSymbol; - localDescription = ip.localDescription; - country = ip.country; - opol = ip.opol; - exchangeData = ip.exchangeData; - exchanges = ip.exchanges; - currency = ip.currency; - baseCurrency = ip.baseCurrency; - cfi = ip.cfi; - isin = ip.isin; - sedol = ip.sedol; - cusip = ip.cusip; - icb = ip.icb; - sic = ip.sic; - multiplier = ip.multiplier; - product = ip.product; - underlying = ip.underlying; - spc = ip.spc; - additionalUnderlyings = ip.additionalUnderlyings; - mmy = ip.mmy; - expiration = ip.expiration; - lastTrade = ip.lastTrade; - strike = ip.strike; - optionType = ip.optionType; - expirationStyle = ip.expirationStyle; - settlementStyle = ip.settlementStyle; - priceIncrements = ip.priceIncrements; - tradingHours = ip.tradingHours; - } + public InstrumentProfile(InstrumentProfile ip) => + handle = InstrumentProfileHandle.Create(ip.GetHandle()); + + internal InstrumentProfile(InstrumentProfileHandle handle) => + this.handle = handle; /// /// Gets or sets type of instrument. @@ -111,8 +50,8 @@ public InstrumentProfile(InstrumentProfile ip) /// "STOCK", "FUTURE", "OPTION". public string Type { - get => type; - set => type = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.Type; + set => handle.Type = value; } /// @@ -123,8 +62,8 @@ public string Type /// "GOOG", "/YGM9", ".ZYEAD". public string Symbol { - get => symbol; - set => symbol = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.Symbol; + set => handle.Symbol = value; } /// @@ -134,8 +73,8 @@ public string Symbol /// "Google Inc.", "Mini Gold Futures,Jun-2009,ETH". public string Description { - get => description; - set => description = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.Description; + set => handle.Description = value; } /// @@ -144,8 +83,8 @@ public string Description /// public string LocalSymbol { - get => localSymbol; - set => localSymbol = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.LocalSymbol; + set => handle.LocalSymbol = value; } /// @@ -154,8 +93,8 @@ public string LocalSymbol /// public string LocalDescription { - get => localDescription; - set => localDescription = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.LocalDescription; + set => handle.LocalDescription = value; } /// @@ -166,8 +105,8 @@ public string LocalDescription /// "US", "RU". public string Country { - get => country; - set => country = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.Country; + set => handle.Country = value; } /// @@ -180,8 +119,8 @@ public string Country /// "XNAS", "RTSX". public string OPOL { - get => opol; - set => opol = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.OPOL; + set => handle.OPOL = value; } /// @@ -190,13 +129,13 @@ public string OPOL /// public string ExchangeData { - get => exchangeData; - set => exchangeData = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.ExchangeData; + set => handle.ExchangeData = value; } /// /// Gets or sets list of exchanges where instrument is quoted or traded. - /// Its shall use the following format: + /// It shall use the following format: /// /// <VALUE> ::= <empty> | <LIST> /// <IST> ::= <MIC> | <MIC> <semicolon> @@ -206,8 +145,8 @@ public string ExchangeData /// "ARCX;CBSX;XNAS;XNYS". public string Exchanges { - get => exchanges; - set => exchanges = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.Exchanges; + set => handle.Exchanges = value; } /// @@ -218,8 +157,8 @@ public string Exchanges /// "USD", "RUB". public string Currency { - get => currency; - set => currency = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.Currency; + set => handle.Currency = value; } /// @@ -228,8 +167,8 @@ public string Currency /// public string BaseCurrency { - get => baseCurrency; - set => baseCurrency = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.BaseCurrency; + set => handle.BaseCurrency = value; } /// @@ -243,8 +182,8 @@ public string BaseCurrency /// "ESNTPB", "ESXXXX", "ES", "OPASPS". public string CFI { - get => cfi; - set => cfi = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.CFI; + set => handle.CFI = value; } /// @@ -256,8 +195,8 @@ public string CFI /// "DE0007100000", "US38259P5089". public string ISIN { - get => isin; - set => isin = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.ISIN; + set => handle.ISIN = value; } /// @@ -269,8 +208,8 @@ public string ISIN /// "2310967", "5766857". public string SEDOL { - get => sedol; - set => sedol = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.SEDOL; + set => handle.SEDOL = value; } /// @@ -281,8 +220,8 @@ public string SEDOL /// "38259P508". public string CUSIP { - get => cusip; - set => cusip = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.CUSIP; + set => handle.CUSIP = value; } /// @@ -294,8 +233,8 @@ public string CUSIP /// "9535". public int ICB { - get => icb; - set => icb = value; + get => handle.ICB; + set => handle.ICB = value; } /// @@ -307,8 +246,8 @@ public int ICB /// "7371". public int SIC { - get => sic; - set => sic = value; + get => handle.SIC; + set => handle.SIC = value; } /// @@ -317,8 +256,8 @@ public int SIC /// "100", "33.2". public double Multiplier { - get => multiplier; - set => multiplier = value; + get => handle.Multiplier; + set => handle.Multiplier = value; } /// @@ -327,8 +266,8 @@ public double Multiplier /// "/YG". public string Product { - get => product; - set => product = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.Product; + set => handle.Product = value; } /// @@ -337,8 +276,8 @@ public string Product /// "C", "/YGM9". public string Underlying { - get => underlying; - set => underlying = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.Underlying; + set => handle.Underlying = value; } /// @@ -347,8 +286,8 @@ public string Underlying /// "1", "100". public double SPC { - get => spc; - set => spc = value; + get => handle.SPC; + set => handle.SPC = value; } /// @@ -364,8 +303,8 @@ public double SPC /// "SE 50", "FIS 53; US$ 45.46". public string AdditionalUnderlyings { - get => additionalUnderlyings; - set => additionalUnderlyings = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.AdditionalUnderlyings; + set => handle.AdditionalUnderlyings = value; } /// @@ -379,8 +318,8 @@ public string AdditionalUnderlyings /// public string MMY { - get => mmy; - set => mmy = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.MMY; + set => handle.MMY = value; } /// @@ -389,8 +328,8 @@ public string MMY /// DayUtil.GetYearMonthDayByDayId(20090117). public int Expiration { - get => expiration; - set => expiration = value; + get => handle.Expiration; + set => handle.Expiration = value; } /// @@ -399,8 +338,8 @@ public int Expiration /// DayUtil.GetYearMonthDayByDayId(20090117). public int LastTrade { - get => lastTrade; - set => lastTrade = value; + get => handle.LastTrade; + set => handle.LastTrade = value; } /// @@ -409,8 +348,8 @@ public int LastTrade /// "80", "22.5". public double Strike { - get => strike; - set => strike = value; + get => handle.Strike; + set => handle.Strike = value; } /// @@ -428,8 +367,8 @@ public double Strike /// public string OptionType { - get => optionType; - set => optionType = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.OptionType; + set => handle.OptionType = value; } /// @@ -437,8 +376,8 @@ public string OptionType /// public string ExpirationStyle { - get => expirationStyle; - set => expirationStyle = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.ExpirationStyle; + set => handle.ExpirationStyle = value; } /// @@ -446,8 +385,8 @@ public string ExpirationStyle /// public string SettlementStyle { - get => settlementStyle; - set => settlementStyle = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.SettlementStyle; + set => handle.SettlementStyle = value; } /// @@ -463,23 +402,104 @@ public string SettlementStyle /// "0.25", "0.01 3; 0.05". public string PriceIncrements { - get => priceIncrements; - set => priceIncrements = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.PriceIncrements; + set => handle.PriceIncrements = value; } /// /// Gets or sets trading hours specification. + /// See Schedule.GetInstance(string). /// public string TradingHours { - get => tradingHours; - set => tradingHours = string.IsNullOrEmpty(value) ? string.Empty : value; + get => handle.TradingHours; + set => handle.TradingHours = value; } + /// + /// Gets the value of the field with the specified name. + /// + /// The name of the field. + /// The field value, or an empty string if the field does not exist. + public string GetField(string name) => + handle.GetField(name); + + /// + /// Sets the value of the field with the specified name. + /// + /// The name of the field. + /// The value to set for the field. + public void SetField(string name, string value) => + handle.SetField(name, value); + + /// + /// Gets the numeric value of the field with the specified name. + /// + /// The name of the field. + /// The numeric field value. + public double GetNumericField(string name) => + handle.GetNumericField(name); + + /// + /// Sets the numeric value of the field with the specified name. + /// + /// The name of the field. + /// The numeric value to set for the field. + public void SetNumericField(string name, double value) => + handle.SetNumericField(name, value); + + /// + /// Gets the day id value of the date field with the specified name. + /// See . + /// + /// The name of the date field. + /// The day id field value. + public int GetDateField(string name) => + handle.GetDateField(name); + + /// + /// Sets the day id value of the date field with the specified name. + /// See . + /// + /// The name of the date field. + /// The day id value to set for the date field. + public void SetDateField(string name, int value) => + handle.SetDateField(name, value); + + /// + /// Adds names of non-empty custom fields to the specified collection. + /// + /// + /// The collection to which the names of non-empty custom fields will be added. + /// + /// + /// true if changed as a result of the call; otherwise, false. + /// + public bool AddNonEmptyCustomFieldNames(ICollection targetFieldNames) => + handle.AddNonEmptyCustomFieldNames(targetFieldNames); + + /// + /// Determines whether the specified object is equal to the current object. + /// + /// The object to compare with the current object. + /// true if the specified object is equal to the current object; otherwise, false. + public override bool Equals(object? obj) => + obj is InstrumentProfile ip && handle.Equals(ip.GetHandle()); + + /// + /// Returns a hash code value for this object. + /// + /// A hash code value for this object. + public override int GetHashCode() => + handle.GetHashCode(); + /// /// Returns a string representation of the instrument profile. /// /// The string representation. public override string ToString() => - $"{Type} {Symbol}"; + handle.ToString(); + + internal InstrumentProfileHandle GetHandle() => + handle; } diff --git a/src/DxFeed.Graal.Net/Ipf/InstrumentProfileReader.cs b/src/DxFeed.Graal.Net/Ipf/InstrumentProfileReader.cs index 825742e7..9b4cec2d 100644 --- a/src/DxFeed.Graal.Net/Ipf/InstrumentProfileReader.cs +++ b/src/DxFeed.Graal.Net/Ipf/InstrumentProfileReader.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using DxFeed.Graal.Net.Auth; +using DxFeed.Graal.Net.Ipf.Live; using DxFeed.Graal.Net.Native.Ipf; namespace DxFeed.Graal.Net.Ipf; @@ -14,10 +15,11 @@ namespace DxFeed.Graal.Net.Ipf; /// Reads instrument profiles from the stream using Instrument Profile Format (IPF). /// Please see Instrument Profile Format documentation for complete description. /// This reader automatically uses data formats as specified in the stream. -///
-/// This reader is intended for "one time only" usage: create new instances for new IPF reads. -///
-/// For backward compatibility reader can be configured with system property "com.dxfeed.ipf.complete" to control +/// +///

This reader is intended for "one time only" usage: create new instances for new IPF reads. +///

Use if support for streaming updates of instrument profiles is needed. +/// +///

For backward compatibility reader can be configured with system property "com.dxfeed.ipf.complete" to control /// the strategy for missing "##COMPLETE" tag when reading IPF, possible values are: ///

    ///
  • warn - show warning in the log (default)
  • @@ -27,7 +29,7 @@ namespace DxFeed.Graal.Net.Ipf; ///
public class InstrumentProfileReader { - private readonly InstrumentProfileReaderNative ipfReaderNative = InstrumentProfileReaderNative.Create(); + private readonly InstrumentProfileReaderHandle ipfReaderNative = InstrumentProfileReaderHandle.Create(); /// /// Resolves the given address specification into its corresponding URL format, particularly transforming @@ -43,10 +45,10 @@ public class InstrumentProfileReader /// The address specification to be resolved into a URL. /// The resolved URL corresponding to the specified address. public static string? ResolveSourceUrl(string address) => - InstrumentProfileReaderNative.ResolveSourceUrl(address); + InstrumentProfileReaderHandle.ResolveSourceUrl(address); /// - /// Returns last modification time (in milliseconds) from last operation + /// Gets last modification time (in milliseconds) from last operation /// or zero if it is unknown. /// /// The last modification time. @@ -66,11 +68,11 @@ public bool WasComplete() => /// In case of zip the first file entry will be read and parsed as a plain data stream. /// In case of gzip compressed content will be read and processed. /// In other cases data considered uncompressed and will be parsed as is. - ///
- /// Authentication information can be supplied to this method as part of URL user info + /// + ///

Authentication information can be supplied to this method as part of URL user info /// like "http://user:password@host:port/path/file.ipf". - ///
- /// This operation updates and . + /// + ///

This operation updates and . ///

/// The URL of file to read from. /// The list of instrument profiles. @@ -83,11 +85,11 @@ public List ReadFromFile(string address) => /// In case of zip the first file entry will be read and parsed as a plain data stream. /// In case of gzip compressed content will be read and processed. /// In other cases data considered uncompressed and will be parsed as is. - ///
- /// Specified user and password take precedence over authentication information that is supplied to this method + /// + ///

Specified user and password take precedence over authentication information that is supplied to this method /// as part of URL user info like "http://user:password@host:port/path/file.ipf". - ///
- /// This operation updates and . + /// + ///

This operation updates and . ///

/// The URL of file to read from. /// The username (maybe null). @@ -106,7 +108,7 @@ public List ReadFromFile(string address, string? user, string ///

Specified token take precedence over authentication information that is supplied to this method /// as part of URL user info like "http://user:password@host:port/path/file.ipf". /// - /// This operation updates and . + ///

This operation updates and . ///

/// The URL of file to read from. /// The token (maybe null). diff --git a/src/DxFeed.Graal.Net/Ipf/Live/InstrumentProfileCollector.cs b/src/DxFeed.Graal.Net/Ipf/Live/InstrumentProfileCollector.cs index 544419f3..965813a7 100644 --- a/src/DxFeed.Graal.Net/Ipf/Live/InstrumentProfileCollector.cs +++ b/src/DxFeed.Graal.Net/Ipf/Live/InstrumentProfileCollector.cs @@ -12,12 +12,16 @@ namespace DxFeed.Graal.Net.Ipf.Live; /// /// Collects instrument profile updates and provides the live list of instrument profiles. /// This class contains a map that keeps a unique instrument profile per symbol. -/// This class is intended to be used with InstrumentProfileConnection as a repository +/// This class is intended to be used with as a repository /// that keeps profiles of all known instruments. -/// As set of instrument profiles stored in this collector can be accessed with view method. -/// A snapshot plus a live stream of updates can be accessed with addUpdateListener method. -/// Removal of instrument profile is represented by an InstrumentProfile instance -/// with a type equal to InstrumentProfileType.REMOVED. +/// +///
As set of instrument profiles stored in this collector can be accessed with method. +/// A snapshot plus a live stream of updates can be accessed with method. +/// +///
Removal of instrument profile is represented by an instance +/// with a type equal to . +/// +///
This class is thread-safe. ///
public class InstrumentProfileCollector { @@ -58,6 +62,9 @@ public void AddUpdateListener(InstrumentProfileUpdateListener listener) => public void RemoveUpdateListener(InstrumentProfileUpdateListener listener) => handle.RemoveUpdateListener(listener); + internal void UpdateInstrumentProfile(InstrumentProfile ip) => + handle.UpdateInstrumentProfile(ip); + internal InstrumentProfileCollectorHandle GetHandle() => handle; } diff --git a/src/DxFeed.Graal.Net/Native/Interop/InstrumentProfileMarshaler.cs b/src/DxFeed.Graal.Net/Native/Interop/InstrumentProfileMarshaler.cs deleted file mode 100644 index cf589af0..00000000 --- a/src/DxFeed.Graal.Net/Native/Interop/InstrumentProfileMarshaler.cs +++ /dev/null @@ -1,199 +0,0 @@ -// -// Copyright © 2024 Devexperts LLC. All rights reserved. -// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. -// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -// - -using System; -using System.Runtime.InteropServices; -using DxFeed.Graal.Net.Ipf; -using DxFeed.Graal.Net.Native.Graal; -using static DxFeed.Graal.Net.Native.ErrorHandling.ErrorCheck; - -namespace DxFeed.Graal.Net.Native.Interop; - -internal sealed class InstrumentProfileMarshaler : AbstractMarshaler -{ - private static readonly Lazy Instance = new(); - - public static ICustomMarshaler GetInstance(string cookie) => - Instance.Value; - - public override unsafe object? ConvertNativeToManaged(IntPtr native) - { - if (native == IntPtr.Zero) - { - return null; - } - - var profile = (InstrumentProfileNative*)native; - return new InstrumentProfile - { - Type = profile->Type!, - Symbol = profile->Symbol!, - Description = profile->Description!, - LocalSymbol = profile->LocalSymbol!, - LocalDescription = profile->LocalDescription!, - Country = profile->Country!, - OPOL = profile->OPOL!, - ExchangeData = profile->ExchangeData!, - Exchanges = profile->Exchanges!, - Currency = profile->Currency!, - BaseCurrency = profile->BaseCurrency!, - CFI = profile->CFI!, - ISIN = profile->ISIN!, - SEDOL = profile->SEDOL!, - CUSIP = profile->CUSIP!, - ICB = profile->ICB, - SIC = profile->SIC, - Multiplier = profile->Multiplier, - Product = profile->Product!, - Underlying = profile->Underlying!, - SPC = profile->SPC, - AdditionalUnderlyings = profile->AdditionalUnderlyings!, - MMY = profile->MMY!, - Expiration = profile->Expiration, - LastTrade = profile->LastTrade, - Strike = profile->Strike, - OptionType = profile->OptionType!, - ExpirationStyle = profile->ExpirationStyle!, - SettlementStyle = profile->SettlementStyle!, - PriceIncrements = profile->PriceIncrements!, - TradingHours = profile->TradingHours!, - }; - } - - public override unsafe IntPtr ConvertManagedToNative(object? managed) - { - if (managed is not InstrumentProfile profile) - { - throw new ArgumentException("Managed object must be a InstrumentProfile.", nameof(managed)); - } - - var ptr = (InstrumentProfileNative*)Marshal.AllocHGlobal(sizeof(InstrumentProfileNative)); - *ptr = new InstrumentProfileNative - { - Type = profile.Type, - Symbol = profile.Symbol, - Description = profile.Description, - LocalSymbol = profile.LocalSymbol, - LocalDescription = profile.LocalDescription, - Country = profile.Country, - OPOL = profile.OPOL, - ExchangeData = profile.ExchangeData, - Exchanges = profile.Exchanges, - Currency = profile.Currency, - BaseCurrency = profile.BaseCurrency, - CFI = profile.CFI, - ISIN = profile.ISIN, - SEDOL = profile.SEDOL, - CUSIP = profile.CUSIP, - ICB = profile.ICB, - SIC = profile.SIC, - Multiplier = profile.Multiplier, - Product = profile.Product, - Underlying = profile.Underlying, - SPC = profile.SPC, - AdditionalUnderlyings = profile.AdditionalUnderlyings, - MMY = profile.MMY, - Expiration = profile.Expiration, - LastTrade = profile.LastTrade, - Strike = profile.Strike, - OptionType = profile.OptionType, - ExpirationStyle = profile.ExpirationStyle, - SettlementStyle = profile.SettlementStyle, - PriceIncrements = profile.PriceIncrements, - TradingHours = profile.TradingHours, - CustomFields = IntPtr.Zero, - }; - return (IntPtr)ptr; - } - - public override unsafe void CleanUpFromManaged(IntPtr ptr) - { - var profile = (InstrumentProfileNative*)ptr; - profile->Type.Release(); - profile->Symbol.Release(); - profile->Description.Release(); - profile->LocalSymbol.Release(); - profile->LocalDescription.Release(); - profile->Country.Release(); - profile->OPOL.Release(); - profile->ExchangeData.Release(); - profile->Exchanges.Release(); - profile->Currency.Release(); - profile->BaseCurrency.Release(); - profile->CFI.Release(); - profile->ISIN.Release(); - profile->SEDOL.Release(); - profile->CUSIP.Release(); - profile->Product.Release(); - profile->Underlying.Release(); - profile->AdditionalUnderlyings.Release(); - profile->MMY.Release(); - profile->OptionType.Release(); - profile->ExpirationStyle.Release(); - profile->SettlementStyle.Release(); - profile->PriceIncrements.Release(); - profile->TradingHours.Release(); - Marshal.FreeHGlobal((IntPtr)profile); - } - - public override void CleanUpFromNative(IntPtr ptr) => - SafeCall(Import.Release(Isolate.CurrentThread, ptr)); - - public override void CleanUpListFromNative(IntPtr ptr) => - SafeCall(Import.ReleaseList(Isolate.CurrentThread, ptr)); - - [StructLayout(LayoutKind.Sequential)] - private record struct InstrumentProfileNative( - StringNative Type, - StringNative Symbol, - StringNative Description, - StringNative LocalSymbol, - StringNative LocalDescription, - StringNative Country, - StringNative OPOL, - StringNative ExchangeData, - StringNative Exchanges, - StringNative Currency, - StringNative BaseCurrency, - StringNative CFI, - StringNative ISIN, - StringNative SEDOL, - StringNative CUSIP, - int ICB, - int SIC, - double Multiplier, - StringNative Product, - StringNative Underlying, - double SPC, - StringNative AdditionalUnderlyings, - StringNative MMY, - int Expiration, - int LastTrade, - double Strike, - StringNative OptionType, - StringNative ExpirationStyle, - StringNative SettlementStyle, - StringNative PriceIncrements, - StringNative TradingHours, - IntPtr CustomFields); - - private static class Import - { - [DllImport( - ImportInfo.DllName, - CallingConvention = CallingConvention.Cdecl, - CharSet = CharSet.Ansi, - EntryPoint = "dxfg_InstrumentProfile_release")] - public static extern int Release(nint thread, nint handle); - - [DllImport( - ImportInfo.DllName, - CallingConvention = CallingConvention.Cdecl, - CharSet = CharSet.Ansi, - EntryPoint = "dxfg_CList_InstrumentProfile_release")] - public static extern int ReleaseList(nint thread, nint handle); - } -} diff --git a/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileCollectorHandle.cs b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileCollectorHandle.cs index 658dc51e..9a4baed5 100644 --- a/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileCollectorHandle.cs +++ b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileCollectorHandle.cs @@ -11,7 +11,6 @@ using DxFeed.Graal.Net.Ipf.Live; using DxFeed.Graal.Net.Native.ErrorHandling; using DxFeed.Graal.Net.Native.Interop; -using DxFeed.Graal.Net.Native.Ipf.Handles; namespace DxFeed.Graal.Net.Native.Ipf; @@ -26,6 +25,9 @@ public static InstrumentProfileCollectorHandle Create() => public long GetLastUpdateTime() => ErrorCheck.SafeCall(NativeGetLastUpdateTime(CurrentThread, this)); + public void UpdateInstrumentProfile(InstrumentProfile ip) => + ErrorCheck.SafeCall(NativeUpdateInstrumentProfile(CurrentThread, this, ip.GetHandle())); + public IEnumerable View() { using var it = ErrorCheck.SafeCall(NativeView(CurrentThread, this)); @@ -68,6 +70,16 @@ private static extern long NativeGetLastUpdateTime( nint thread, InstrumentProfileCollectorHandle collector); + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + EntryPoint = "dxfg_InstrumentProfileCollector_updateInstrumentProfile")] + private static extern int NativeUpdateInstrumentProfile( + nint thread, + InstrumentProfileCollectorHandle collector, + InstrumentProfileHandle ip); + [DllImport( ImportInfo.DllName, CallingConvention = CallingConvention.Cdecl, diff --git a/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileHandle.cs b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileHandle.cs new file mode 100644 index 00000000..a01423e3 --- /dev/null +++ b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileHandle.cs @@ -0,0 +1,1106 @@ +// +// Copyright © 2024 Devexperts LLC. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using DxFeed.Graal.Net.Ipf; +using DxFeed.Graal.Net.Native.Interop; +using static DxFeed.Graal.Net.Native.ErrorHandling.ErrorCheck; + +namespace DxFeed.Graal.Net.Native.Ipf; + +internal class InstrumentProfileHandle : JavaHandle +{ + public InstrumentProfileHandle() + { + } + + public InstrumentProfileHandle(IntPtr handle) + : base(handle) + { + } + + public string Type + { + get => SafeCall(Import.GetType(CurrentThread, this)); + set => SafeCall(Import.SetType(CurrentThread, this, value)); + } + + public string Symbol + { + get => SafeCall(Import.GetSymbol(CurrentThread, this)); + set => SafeCall(Import.SetSymbol(CurrentThread, this, value)); + } + + public string Description + { + get => SafeCall(Import.GetDescription(CurrentThread, this)); + set => SafeCall(Import.SetDescription(CurrentThread, this, value)); + } + + public string LocalSymbol + { + get => SafeCall(Import.GetLocalSymbol(CurrentThread, this)); + set => SafeCall(Import.SetLocalSymbol(CurrentThread, this, value)); + } + + public string LocalDescription + { + get => SafeCall(Import.GetLocalDescription(CurrentThread, this)); + set => SafeCall(Import.SetLocalDescription(CurrentThread, this, value)); + } + + public string Country + { + get => SafeCall(Import.GetCountry(CurrentThread, this)); + set => SafeCall(Import.SetCountry(CurrentThread, this, value)); + } + + public string OPOL + { + get => SafeCall(Import.GetOPOL(CurrentThread, this)); + set => SafeCall(Import.SetOPOL(CurrentThread, this, value)); + } + + public string ExchangeData + { + get => SafeCall(Import.GetExchangeData(CurrentThread, this)); + set => SafeCall(Import.SetExchangeData(CurrentThread, this, value)); + } + + public string Exchanges + { + get => SafeCall(Import.GetExchanges(CurrentThread, this)); + set => SafeCall(Import.SetExchanges(CurrentThread, this, value)); + } + + public string Currency + { + get => SafeCall(Import.GetCurrency(CurrentThread, this)); + set => SafeCall(Import.SetCurrency(CurrentThread, this, value)); + } + + public string BaseCurrency + { + get => SafeCall(Import.GetBaseCurrency(CurrentThread, this)); + set => SafeCall(Import.SetBaseCurrency(CurrentThread, this, value)); + } + + public string CFI + { + get => SafeCall(Import.GetCFI(CurrentThread, this)); + set => SafeCall(Import.SetCFI(CurrentThread, this, value)); + } + + public string ISIN + { + get => SafeCall(Import.GetISIN(CurrentThread, this)); + set => SafeCall(Import.SetISIN(CurrentThread, this, value)); + } + + public string SEDOL + { + get => SafeCall(Import.GetSEDOL(CurrentThread, this)); + set => SafeCall(Import.SetSEDOL(CurrentThread, this, value)); + } + + public string CUSIP + { + get => SafeCall(Import.GetCUSIP(CurrentThread, this)); + set => SafeCall(Import.SetCUSIP(CurrentThread, this, value)); + } + + public int ICB + { + get => SafeCall(Import.GetICB(CurrentThread, this)); + set => SafeCall(Import.SetICB(CurrentThread, this, value)); + } + + public int SIC + { + get => SafeCall(Import.GetSIC(CurrentThread, this)); + set => SafeCall(Import.SetSIC(CurrentThread, this, value)); + } + + public double Multiplier + { + get => SafeCall(Import.GetMultiplier(CurrentThread, this)); + set => SafeCall(Import.SetMultiplier(CurrentThread, this, value)); + } + + public string Product + { + get => SafeCall(Import.GetProduct(CurrentThread, this)); + set => SafeCall(Import.SetProduct(CurrentThread, this, value)); + } + + public string Underlying + { + get => SafeCall(Import.GetUnderlying(CurrentThread, this)); + set => SafeCall(Import.SetUnderlying(CurrentThread, this, value)); + } + + public double SPC + { + get => SafeCall(Import.GetSPC(CurrentThread, this)); + set => SafeCall(Import.SetSPC(CurrentThread, this, value)); + } + + public string AdditionalUnderlyings + { + get => SafeCall(Import.GetAdditionalUnderlyings(CurrentThread, this)); + set => SafeCall(Import.SetAdditionalUnderlyings(CurrentThread, this, value)); + } + + public string MMY + { + get => SafeCall(Import.GetMMY(CurrentThread, this)); + set => SafeCall(Import.SetMMY(CurrentThread, this, value)); + } + + public int Expiration + { + get => SafeCall(Import.GetExpiration(CurrentThread, this)); + set => SafeCall(Import.SetExpiration(CurrentThread, this, value)); + } + + public int LastTrade + { + get => SafeCall(Import.GetLastTrade(CurrentThread, this)); + set => SafeCall(Import.SetLastTrade(CurrentThread, this, value)); + } + + public double Strike + { + get => SafeCall(Import.GetStrike(CurrentThread, this)); + set => SafeCall(Import.SetStrike(CurrentThread, this, value)); + } + + public string OptionType + { + get => SafeCall(Import.GetOptionType(CurrentThread, this)); + set => SafeCall(Import.SetOptionType(CurrentThread, this, value)); + } + + public string ExpirationStyle + { + get => SafeCall(Import.GetExpirationStyle(CurrentThread, this)); + set => SafeCall(Import.SetExpirationStyle(CurrentThread, this, value)); + } + + public string SettlementStyle + { + get => SafeCall(Import.GetSettlementStyle(CurrentThread, this)); + set => SafeCall(Import.SetSettlementStyle(CurrentThread, this, value)); + } + + public string PriceIncrements + { + get => SafeCall(Import.GetPriceIncrements(CurrentThread, this)); + set => SafeCall(Import.SetPriceIncrements(CurrentThread, this, value)); + } + + public string TradingHours + { + get => SafeCall(Import.GetTradingHours(CurrentThread, this)); + set => SafeCall(Import.SetTradingHours(CurrentThread, this, value)); + } + + public static InstrumentProfileHandle Create() => + SafeCall(Import.Create(CurrentThread)); + + public static InstrumentProfileHandle Create(InstrumentProfileHandle handle) => + SafeCall(Import.Create(CurrentThread, handle)); + + public string GetField(string name) => + SafeCall(Import.GetField(CurrentThread, this, name)); + + public void SetField(string name, string value) => + SafeCall(Import.SetField(CurrentThread, this, name, value)); + + public double GetNumericField(string name) => + SafeCall(Import.GetNumericField(CurrentThread, this, name)); + + public void SetNumericField(string name, double value) => + SafeCall(Import.SetNumericField(CurrentThread, this, name, value)); + + public int GetDateField(string name) => + SafeCall(Import.GetDateField(CurrentThread, this, name)); + + public void SetDateField(string name, int value) => + SafeCall(Import.SetDateField(CurrentThread, this, name, value)); + + public bool AddNonEmptyCustomFieldNames(ICollection targetFieldNames) + { + var fields = SafeCall(Import.GetNonEmptyCustomFieldNames(CurrentThread, this)); + foreach (var field in fields) + { + targetFieldNames.Add(field); + } + + return fields.Count != 0; + } + + private static class Import + { + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + EntryPoint = "dxfg_InstrumentProfile_new")] + public static extern InstrumentProfileHandle Create(nint thread); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + EntryPoint = "dxfg_InstrumentProfile_new2")] + public static extern InstrumentProfileHandle Create(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getType")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetType(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setType")] + public static extern int SetType( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getSymbol")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetSymbol(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setSymbol")] + public static extern int SetSymbol( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getDescription")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetDescription(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setDescription")] + public static extern int SetDescription( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getLocalSymbol")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetLocalSymbol(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setLocalSymbol")] + public static extern int SetLocalSymbol( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getLocalDescription")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetLocalDescription(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setLocalDescription")] + public static extern int SetLocalDescription( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getCountry")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetCountry(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setCountry")] + public static extern int SetCountry( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getOPOL")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetOPOL(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setOPOL")] + public static extern int SetOPOL( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getExchangeData")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetExchangeData(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setExchangeData")] + public static extern int SetExchangeData( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getExchanges")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetExchanges(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setExchanges")] + public static extern int SetExchanges( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getCurrency")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetCurrency(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setCurrency")] + public static extern int SetCurrency( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getBaseCurrency")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetBaseCurrency(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setBaseCurrency")] + public static extern int SetBaseCurrency( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getCFI")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetCFI(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setCFI")] + public static extern int SetCFI( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getISIN")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetISIN(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setISIN")] + public static extern int SetISIN( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getSEDOL")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetSEDOL(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setSEDOL")] + public static extern int SetSEDOL( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getCUSIP")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetCUSIP(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setCUSIP")] + public static extern int SetCUSIP( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getICB")] + public static extern int GetICB(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setICB")] + public static extern int SetICB(nint thread, InstrumentProfileHandle ip, int value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getSIC")] + public static extern int GetSIC(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setSIC")] + public static extern int SetSIC(nint thread, InstrumentProfileHandle ip, int value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getMultiplier")] + public static extern double GetMultiplier(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setMultiplier")] + public static extern int SetMultiplier(nint thread, InstrumentProfileHandle ip, double value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getProduct")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetProduct(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setProduct")] + public static extern int SetProduct( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getUnderlying")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetUnderlying(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setUnderlying")] + public static extern int SetUnderlying( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getSPC")] + public static extern double GetSPC(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setSPC")] + public static extern int SetSPC(nint thread, InstrumentProfileHandle ip, double value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getAdditionalUnderlyings")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetAdditionalUnderlyings(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setAdditionalUnderlyings")] + public static extern int SetAdditionalUnderlyings( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getMMY")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetMMY(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setMMY")] + public static extern int SetMMY( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getExpiration")] + public static extern int GetExpiration(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setExpiration")] + public static extern int SetExpiration(nint thread, InstrumentProfileHandle ip, int value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getLastTrade")] + public static extern int GetLastTrade(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setLastTrade")] + public static extern int SetLastTrade(nint thread, InstrumentProfileHandle ip, int value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getStrike")] + public static extern double GetStrike(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setStrike")] + public static extern int SetStrike(nint thread, InstrumentProfileHandle ip, double value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getOptionType")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetOptionType(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setOptionType")] + public static extern int SetOptionType( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getExpirationStyle")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetExpirationStyle(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setExpirationStyle")] + public static extern int SetExpirationStyle( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getSettlementStyle")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetSettlementStyle(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setSettlementStyle")] + public static extern int SetSettlementStyle( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getPriceIncrements")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetPriceIncrements(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setPriceIncrements")] + public static extern int SetPriceIncrements( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getTradingHours")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetTradingHours(nint thread, InstrumentProfileHandle ip); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setTradingHours")] + public static extern int SetTradingHours( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getField")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string GetField( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string name); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setField")] + public static extern int SetField( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string name, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getNumericField")] + public static extern double GetNumericField( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string name); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setNumericField")] + public static extern int SetNumericField( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string name, + double value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getDateField")] + public static extern int GetDateField( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string name); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_setDateField")] + public static extern int SetDateField( + nint thread, + InstrumentProfileHandle ip, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string name, + int value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfile_getNonEmptyCustomFieldNames")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ListMarshaler))] + public static extern List GetNonEmptyCustomFieldNames( + nint thread, + InstrumentProfileHandle ip); + } +} diff --git a/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileListNative.cs b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileListNative.cs deleted file mode 100644 index 6b381a03..00000000 --- a/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileListNative.cs +++ /dev/null @@ -1,58 +0,0 @@ -// -// Copyright © 2022 Devexperts LLC. All rights reserved. -// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. -// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -// - -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using DxFeed.Graal.Net.Ipf; -using DxFeed.Graal.Net.Native.ErrorHandling; -using DxFeed.Graal.Net.Native.Interop; - -namespace DxFeed.Graal.Net.Native.Ipf; - -internal sealed class InstrumentProfileListNative : JavaHandle -{ - public unsafe List ToList() - { - var result = new List(); - var profiles = (ListNative*)handle; - for (var i = 0; i < profiles->Size; i++) - { - result.Add(InstrumentProfileMapper.Convert(profiles->Elements[i])); - } - - return result; - } - - protected override bool ReleaseHandle() - { - try - { - ErrorCheck.SafeCall(NativeRelease(CurrentThread, handle)); - handle = (IntPtr)0; - return true; - } - catch (Exception e) - { - // ToDo Add a log entry. - Console.Error.WriteLine($"Exception in {GetType().Name} when releasing resource: {e}"); - } - - return false; - } - - [DllImport( - ImportInfo.DllName, - CallingConvention = CallingConvention.Cdecl, - CharSet = CharSet.Ansi, - ExactSpelling = true, - BestFitMapping = false, - ThrowOnUnmappableChar = true, - EntryPoint = "dxfg_CList_InstrumentProfile_release")] - private static extern int NativeRelease( - nint thread, - nint instrumentProfileList); -} diff --git a/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileMapper.cs b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileMapper.cs deleted file mode 100644 index a0fb5c38..00000000 --- a/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileMapper.cs +++ /dev/null @@ -1,48 +0,0 @@ -// -// Copyright © 2022 Devexperts LLC. All rights reserved. -// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. -// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -// - -using DxFeed.Graal.Net.Ipf; - -namespace DxFeed.Graal.Net.Native.Ipf; - -internal static class InstrumentProfileMapper -{ - public static unsafe InstrumentProfile Convert(InstrumentProfileNative* eventType) => - new() - { - Type = eventType->Type!, - Symbol = eventType->Symbol!, - Description = eventType->Description!, - LocalSymbol = eventType->LocalSymbol!, - LocalDescription = eventType->LocalDescription!, - Country = eventType->Country!, - OPOL = eventType->OPOL!, - ExchangeData = eventType->ExchangeData!, - Exchanges = eventType->Exchanges!, - Currency = eventType->Currency!, - BaseCurrency = eventType->BaseCurrency!, - CFI = eventType->CFI!, - ISIN = eventType->ISIN!, - SEDOL = eventType->SEDOL!, - CUSIP = eventType->CUSIP!, - ICB = eventType->ICB, - SIC = eventType->SIC, - Multiplier = eventType->Multiplier, - Product = eventType->Product!, - Underlying = eventType->Underlying!, - SPC = eventType->SPC, - AdditionalUnderlyings = eventType->AdditionalUnderlyings!, - MMY = eventType->MMY!, - Expiration = eventType->Expiration, - LastTrade = eventType->LastTrade, - Strike = eventType->Strike, - OptionType = eventType->OptionType!, - ExpirationStyle = eventType->ExpirationStyle!, - SettlementStyle = eventType->SettlementStyle!, - PriceIncrements = eventType->PriceIncrements!, - TradingHours = eventType->TradingHours!, - }; -} diff --git a/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileNative.cs b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileNative.cs deleted file mode 100644 index 0e52eff7..00000000 --- a/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileNative.cs +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright © 2024 Devexperts LLC. All rights reserved. -// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. -// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -// - -using System.Runtime.InteropServices; -using DxFeed.Graal.Net.Native.Interop; - -namespace DxFeed.Graal.Net.Native.Ipf; - -[StructLayout(LayoutKind.Sequential)] -internal record struct InstrumentProfileNative( - StringNative Type, - StringNative Symbol, - StringNative Description, - StringNative LocalSymbol, - StringNative LocalDescription, - StringNative Country, - StringNative OPOL, - StringNative ExchangeData, - StringNative Exchanges, - StringNative Currency, - StringNative BaseCurrency, - StringNative CFI, - StringNative ISIN, - StringNative SEDOL, - StringNative CUSIP, - int ICB, - int SIC, - double Multiplier, - StringNative Product, - StringNative Underlying, - double SPC, - StringNative AdditionalUnderlyings, - StringNative MMY, - int Expiration, - int LastTrade, - double Strike, - StringNative OptionType, - StringNative ExpirationStyle, - StringNative SettlementStyle, - StringNative PriceIncrements, - StringNative TradingHours); diff --git a/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileReaderHandle.cs b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileReaderHandle.cs new file mode 100644 index 00000000..0cb33c65 --- /dev/null +++ b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileReaderHandle.cs @@ -0,0 +1,151 @@ +// +// Copyright © 2024 Devexperts LLC. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using DxFeed.Graal.Net.Auth; +using DxFeed.Graal.Net.Ipf; +using DxFeed.Graal.Net.Native.Auth; +using DxFeed.Graal.Net.Native.Interop; +using static DxFeed.Graal.Net.Native.ErrorHandling.ErrorCheck; + +namespace DxFeed.Graal.Net.Native.Ipf; + +[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "Created by marshaler")] +internal sealed class InstrumentProfileReaderHandle : JavaHandle +{ + public static string? ResolveSourceUrl(string address) => + SafeCall(Import.ResolveSourceUrl(CurrentThread, address)); + + public static InstrumentProfileReaderHandle Create() => + SafeCall(Import.NativeCreate(CurrentThread)); + + public long GetLastModified() => + SafeCall(Import.GetLastModified(CurrentThread, this)); + + public bool WasComplete() => + SafeCall(Import.WasComplete(CurrentThread, this)) != 0; + + public unsafe List ReadFromFile(string address, string? user, string? password) + { + var ptr = SafeCall(Import.ReadFromFile(CurrentThread, this, address, user, password)); + return ConvertToProfiles(ptr); + } + + public unsafe List ReadFromFile(string address, AuthToken? authToken) + { + var tokenHandle = authToken == null ? new AuthTokenHandle() : authToken.Handle; + var ptr = SafeCall(Import.ReadFromFile(CurrentThread, this, address, tokenHandle)); + return ConvertToProfiles(ptr); + } + + private unsafe List ConvertToProfiles(ListNative* handles) + { + try + { + var profiles = new List(); + for (var i = 0; i < handles->Size; i++) + { + profiles.Add(new InstrumentProfile(new InstrumentProfileHandle((IntPtr)handles->Elements[i]))); + } + + return profiles; + } + finally + { + SafeCall(Import.ReleaseListWrapper(CurrentThread, handles)); + } + } + + private static class Import + { + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfileReader_resolveSourceURL")] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + public static extern string? ResolveSourceUrl( + nint thread, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string address); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + EntryPoint = "dxfg_InstrumentProfileReader_new")] + public static extern InstrumentProfileReaderHandle NativeCreate(nint thread); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + EntryPoint = "dxfg_InstrumentProfileReader_getLastModified")] + public static extern long GetLastModified( + nint thread, + InstrumentProfileReaderHandle reader); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + EntryPoint = "dxfg_InstrumentProfileReader_wasComplete")] + public static extern int WasComplete( + nint thread, + InstrumentProfileReaderHandle reader); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfileReader_readFromFile2")] + public static extern unsafe ListNative* ReadFromFile( + nint thread, + InstrumentProfileReaderHandle reader, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string address, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string? user, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string? password); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfileReader_readFromFile3")] + public static extern unsafe ListNative* ReadFromFile( + nint thread, + InstrumentProfileReaderHandle reader, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string address, + AuthTokenHandle authToken); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_CList_InstrumentProfile_wrapper_release")] + public static extern unsafe ListNative* ReleaseListWrapper( + nint thread, + ListNative* list); + } +} diff --git a/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileReaderNative.cs b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileReaderNative.cs deleted file mode 100644 index 1d4f1f41..00000000 --- a/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileReaderNative.cs +++ /dev/null @@ -1,110 +0,0 @@ -// -// Copyright © 2024 Devexperts LLC. All rights reserved. -// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. -// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -// - -using System.Collections.Generic; -using System.Runtime.InteropServices; -using DxFeed.Graal.Net.Auth; -using DxFeed.Graal.Net.Ipf; -using DxFeed.Graal.Net.Native.Auth; -using DxFeed.Graal.Net.Native.Interop; -using static DxFeed.Graal.Net.Native.ErrorHandling.ErrorCheck; - -namespace DxFeed.Graal.Net.Native.Ipf; - -internal sealed class InstrumentProfileReaderNative : JavaHandle -{ - public static string? ResolveSourceUrl(string address) => - SafeCall(NativeResolveSourceUrl(CurrentThread, address)); - - public static InstrumentProfileReaderNative Create() => - SafeCall(NativeCreate(CurrentThread)); - - public long GetLastModified() => - SafeCall(NativeGetLastModified(CurrentThread, this)); - - public bool WasComplete() => - SafeCall(NativeWasComplete(CurrentThread, this)) != 0; - - public List ReadFromFile(string address, string? user, string? password) - { - using var result = SafeCall(NativeReadFromFile(CurrentThread, this, address, user, password)); - return result.ToList(); - } - - public List ReadFromFile(string address, AuthToken? authToken) - { - var tokenHandle = authToken == null ? new AuthTokenHandle() : authToken.Handle; - using var result = SafeCall(NativeReadFromFile(CurrentThread, this, address, tokenHandle)); - return result.ToList(); - } - - [DllImport( - ImportInfo.DllName, - CallingConvention = CallingConvention.Cdecl, - CharSet = CharSet.Ansi, - ExactSpelling = true, - BestFitMapping = false, - ThrowOnUnmappableChar = true, - EntryPoint = "dxfg_InstrumentProfileReader_resolveSourceURL")] - [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] - private static extern string? NativeResolveSourceUrl( - nint thread, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] string address); - - [DllImport( - ImportInfo.DllName, - CallingConvention = CallingConvention.Cdecl, - CharSet = CharSet.Ansi, - EntryPoint = "dxfg_InstrumentProfileReader_new")] - private static extern InstrumentProfileReaderNative NativeCreate(nint thread); - - [DllImport( - ImportInfo.DllName, - CallingConvention = CallingConvention.Cdecl, - CharSet = CharSet.Ansi, - EntryPoint = "dxfg_InstrumentProfileReader_getLastModified")] - private static extern long NativeGetLastModified( - nint thread, - InstrumentProfileReaderNative reader); - - [DllImport( - ImportInfo.DllName, - CallingConvention = CallingConvention.Cdecl, - CharSet = CharSet.Ansi, - EntryPoint = "dxfg_InstrumentProfileReader_wasComplete")] - private static extern int NativeWasComplete( - nint thread, - InstrumentProfileReaderNative reader); - - [DllImport( - ImportInfo.DllName, - CallingConvention = CallingConvention.Cdecl, - CharSet = CharSet.Ansi, - ExactSpelling = true, - BestFitMapping = false, - ThrowOnUnmappableChar = true, - EntryPoint = "dxfg_InstrumentProfileReader_readFromFile2")] - private static extern InstrumentProfileListNative NativeReadFromFile( - nint thread, - InstrumentProfileReaderNative reader, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] string address, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] string? user, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] string? password); - - [DllImport( - ImportInfo.DllName, - CallingConvention = CallingConvention.Cdecl, - CharSet = CharSet.Ansi, - ExactSpelling = true, - BestFitMapping = false, - ThrowOnUnmappableChar = true, - EntryPoint = "dxfg_InstrumentProfileReader_readFromFile3")] - private static extern InstrumentProfileListNative NativeReadFromFile( - nint thread, - InstrumentProfileReaderNative reader, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] string address, - AuthTokenHandle authToken); -} diff --git a/src/DxFeed.Graal.Net/Native/Ipf/Handles/InstrumentProfileUpdateListenerHandle.cs b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileUpdateListenerHandle.cs similarity index 97% rename from src/DxFeed.Graal.Net/Native/Ipf/Handles/InstrumentProfileUpdateListenerHandle.cs rename to src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileUpdateListenerHandle.cs index 03b4a5a7..a636e6fa 100644 --- a/src/DxFeed.Graal.Net/Native/Ipf/Handles/InstrumentProfileUpdateListenerHandle.cs +++ b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileUpdateListenerHandle.cs @@ -11,7 +11,7 @@ using DxFeed.Graal.Net.Native.Interop; using static DxFeed.Graal.Net.Native.ErrorHandling.ErrorCheck; -namespace DxFeed.Graal.Net.Native.Ipf.Handles; +namespace DxFeed.Graal.Net.Native.Ipf; [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "Created by marshaler")] internal sealed class InstrumentProfileUpdateListenerHandle : JavaHandle diff --git a/src/DxFeed.Graal.Net/Native/Ipf/Handles/IterableInstrumentProfileHandle.cs b/src/DxFeed.Graal.Net/Native/Ipf/IterableInstrumentProfileHandle.cs similarity index 88% rename from src/DxFeed.Graal.Net/Native/Ipf/Handles/IterableInstrumentProfileHandle.cs rename to src/DxFeed.Graal.Net/Native/Ipf/IterableInstrumentProfileHandle.cs index 62085938..35df6acd 100644 --- a/src/DxFeed.Graal.Net/Native/Ipf/Handles/IterableInstrumentProfileHandle.cs +++ b/src/DxFeed.Graal.Net/Native/Ipf/IterableInstrumentProfileHandle.cs @@ -11,9 +11,9 @@ using DxFeed.Graal.Net.Native.ErrorHandling; using DxFeed.Graal.Net.Native.Interop; -namespace DxFeed.Graal.Net.Native.Ipf.Handles; +namespace DxFeed.Graal.Net.Native.Ipf; -internal sealed unsafe class IterableInstrumentProfileHandle : JavaHandle +internal sealed class IterableInstrumentProfileHandle : JavaHandle { public IterableInstrumentProfileHandle() { @@ -41,7 +41,7 @@ public bool HasNext() => public InstrumentProfile? Next() { var i = NativeNext(CurrentThread, this); - return i != null ? InstrumentProfileMapper.Convert(i) : null; + return i != null ? new InstrumentProfile(i) : null; } [DllImport( @@ -64,7 +64,7 @@ private static extern int NativeHasNext( BestFitMapping = false, ThrowOnUnmappableChar = true, EntryPoint = "dxfg_Iterable_InstrumentProfile_next")] - private static extern InstrumentProfileNative* NativeNext( + private static extern InstrumentProfileHandle? NativeNext( nint thread, IterableInstrumentProfileHandle iterable); } diff --git a/src/DxFeed.Graal.Net/Native/Schedules/ScheduleHandle.cs b/src/DxFeed.Graal.Net/Native/Schedules/ScheduleHandle.cs index 731d99bc..419f86b0 100644 --- a/src/DxFeed.Graal.Net/Native/Schedules/ScheduleHandle.cs +++ b/src/DxFeed.Graal.Net/Native/Schedules/ScheduleHandle.cs @@ -9,6 +9,7 @@ using System.Runtime.InteropServices; using DxFeed.Graal.Net.Ipf; using DxFeed.Graal.Net.Native.Interop; +using DxFeed.Graal.Net.Native.Ipf; using static DxFeed.Graal.Net.Native.ErrorHandling.ErrorCheck; namespace DxFeed.Graal.Net.Native.Schedules; @@ -17,16 +18,16 @@ namespace DxFeed.Graal.Net.Native.Schedules; internal sealed class ScheduleHandle : JavaHandle { public static ScheduleHandle GetInstance(InstrumentProfile profile) => - SafeCall(Import.GetInstance(CurrentThread, profile)); + SafeCall(Import.GetInstance(CurrentThread, profile.GetHandle())); public static ScheduleHandle GetInstance(string scheduleDefinition) => SafeCall(Import.GetInstance(CurrentThread, scheduleDefinition)); public static ScheduleHandle GetInstance(InstrumentProfile profile, string venue) => - SafeCall(Import.GetInstance(CurrentThread, profile, venue)); + SafeCall(Import.GetInstance(CurrentThread, profile.GetHandle(), venue)); public static List GetTradingVenues(InstrumentProfile profile) => - SafeCall(Import.GetTradingVenues(CurrentThread, profile)); + SafeCall(Import.GetTradingVenues(CurrentThread, profile.GetHandle())); public static void DownloadDefaults(string downloadConfig) => SafeCall(Import.DownloadDefaults(CurrentThread, downloadConfig)); @@ -76,8 +77,7 @@ private static class Import EntryPoint = "dxfg_Schedule_getInstance")] public static extern ScheduleHandle GetInstance( nint thread, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(InstrumentProfileMarshaler))] - InstrumentProfile profile); + InstrumentProfileHandle profile); [DllImport( ImportInfo.DllName, @@ -102,8 +102,7 @@ public static extern ScheduleHandle GetInstance( EntryPoint = "dxfg_Schedule_getInstance3")] public static extern ScheduleHandle GetInstance( nint thread, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(InstrumentProfileMarshaler))] - InstrumentProfile profile, + InstrumentProfileHandle profile, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] string venue); @@ -118,8 +117,7 @@ public static extern ScheduleHandle GetInstance( [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ListMarshaler))] public static extern List GetTradingVenues( nint thread, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(InstrumentProfileMarshaler))] - InstrumentProfile profile); + InstrumentProfileHandle profile); [DllImport( ImportInfo.DllName, diff --git a/tests/DxFeed.Graal.Net.Tests/DxFeed.Graal.Net.Tests.csproj b/tests/DxFeed.Graal.Net.Tests/DxFeed.Graal.Net.Tests.csproj index b97eb8ba..c923934d 100644 --- a/tests/DxFeed.Graal.Net.Tests/DxFeed.Graal.Net.Tests.csproj +++ b/tests/DxFeed.Graal.Net.Tests/DxFeed.Graal.Net.Tests.csproj @@ -36,4 +36,10 @@ + + + Always + + + diff --git a/tests/DxFeed.Graal.Net.Tests/Ipf/InstrumentProfileCollectorTest.cs b/tests/DxFeed.Graal.Net.Tests/Ipf/InstrumentProfileCollectorTest.cs new file mode 100644 index 00000000..bf09d632 --- /dev/null +++ b/tests/DxFeed.Graal.Net.Tests/Ipf/InstrumentProfileCollectorTest.cs @@ -0,0 +1,73 @@ +// +// Copyright © 2024 Devexperts LLC. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +using System.Globalization; +using DxFeed.Graal.Net.Ipf; +using DxFeed.Graal.Net.Ipf.Live; + +namespace DxFeed.Graal.Net.Tests.Ipf; + +[TestFixture] +public class InstrumentProfileCollectorTests +{ + private InstrumentProfileCollector collector; + + [SetUp] + public void SetUp() => + collector = new InstrumentProfileCollector(); + + [Test] + public void TestUpdateRemoved() + { + var update0 = collector.GetLastUpdateTime(); + AssertViewIdentities(); // empty + + // first instrument + var i1 = new InstrumentProfile(); + RandomInstrument(i1, 20140618); + collector.UpdateInstrumentProfile(i1); + var update1 = collector.GetLastUpdateTime(); + Assert.That(update1, Is.GreaterThan(update0)); + AssertViewIdentities(i1); + + // second instrument has same symbol but "REMOVED" type + var i2 = new InstrumentProfile(); + RandomInstrument(i2, 20140618); + i2.Type = InstrumentProfileType.REMOVED.Name; + collector.UpdateInstrumentProfile(i2); + var update2 = collector.GetLastUpdateTime(); + Assert.That(update2, Is.GreaterThan(update1)); + AssertViewIdentities(); // becomes empty + + // removed again (nothing shall change) + var i3 = new InstrumentProfile(); + RandomInstrument(i3, 20140618); + i3.Type = InstrumentProfileType.REMOVED.Name; + collector.UpdateInstrumentProfile(i3); + var update3 = collector.GetLastUpdateTime(); + Assert.That(update3, Is.EqualTo(update2)); + AssertViewIdentities(); // becomes empty + } + + private static void RandomInstrument(InstrumentProfile ip, long seed) + { + var r = new Random((int)seed); + ip.Symbol = r.Next(10000).ToString(CultureInfo.InvariantCulture); + } + + private void AssertViewIdentities(params InstrumentProfile[] ips) + { + var expected = new HashSet(ips); + var actual = new HashSet(); + foreach (var instrument in collector.View()) + { + Assert.That(instrument.Type, Is.Not.EqualTo(InstrumentProfileType.REMOVED.Name)); + actual.Add(instrument); + } + + Assert.That(expected, Is.EqualTo(actual)); + } +} diff --git a/tests/DxFeed.Graal.Net.Tests/Ipf/InstrumentProfileReaderTests.cs b/tests/DxFeed.Graal.Net.Tests/Ipf/InstrumentProfileReaderTests.cs new file mode 100644 index 00000000..5996f699 --- /dev/null +++ b/tests/DxFeed.Graal.Net.Tests/Ipf/InstrumentProfileReaderTests.cs @@ -0,0 +1,67 @@ +// +// Copyright © 2024 Devexperts LLC. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +using DxFeed.Graal.Net.Ipf; + +namespace DxFeed.Graal.Net.Tests.Ipf; + +[TestFixture] +public class InstrumentProfileReaderTests +{ + private static readonly string TestIpf = Path.Combine(TestContext.CurrentContext.TestDirectory, "ipf.txt"); + + [Test] + public void ResolveSourceUrl_ShouldReturnUrlFormat_WhenHostPortPatternProvided() + { + var address = "host:7777"; + var expectedUrl = "http://host:7777/ipf/all.ipf.gz"; + + var result = InstrumentProfileReader.ResolveSourceUrl(address); + + Assert.That(result, Is.EqualTo(expectedUrl)); + } + + [Test] + public void ResolveSourceUrl_ShouldReturnOriginalAddress_WhenNotHostPortPattern() + { + var address = "file.txt"; + var result = InstrumentProfileReader.ResolveSourceUrl(address); + + Assert.That(result, Is.EqualTo(address)); + } + + [Test] + public void GetLastModified_ShouldReturnLastModificationTime() + { + var reader = new InstrumentProfileReader(); + Assert.That(reader.WasComplete(), Is.False); + reader.ReadFromFile(TestIpf); + Assert.That(reader.WasComplete(), Is.True); + + var lastFileModified = ((DateTimeOffset)File.GetLastWriteTimeUtc(TestIpf)).ToUnixTimeMilliseconds(); + Assert.That(reader.GetLastModified(), Is.EqualTo(lastFileModified)); + } + + [Test] + public void ReadFromFile_ShouldReturnCorrectsProfiles() + { + var reader = new InstrumentProfileReader(); + var profiles = reader.ReadFromFile(TestIpf); + Assert.That(profiles, Has.Count.EqualTo(31)); + + var profile = profiles.Find(profile => profile.Symbol.Equals("AAPL", StringComparison.Ordinal)); + Assert.That(profile, Is.Not.Null); + Assert.Multiple(() => + { + Assert.That(profile.Description, Is.EqualTo("Apple Inc. - Common Stock")); + Assert.That(profile.Country, Is.EqualTo("US")); + Assert.That(profile.OPOL, Is.EqualTo("XNAS")); + Assert.That(profile.Exchanges, Is.EqualTo("ARCX;BATS;BATY;EDGA;EDGX;IEXG;LTSE;MEMX;MPRL;XADF;XASE;XBOS;XCHI;XCIS;XNAS;XNYS;XPSX")); + Assert.That(profile.Currency, Is.EqualTo("USD")); + Assert.That(profile.GetField("SUBTYPES"), Is.EqualTo("Common Share;")); + }); + } +} diff --git a/tests/DxFeed.Graal.Net.Tests/Ipf/InstrumentProfileTests.cs b/tests/DxFeed.Graal.Net.Tests/Ipf/InstrumentProfileTests.cs new file mode 100644 index 00000000..d30fb7d5 --- /dev/null +++ b/tests/DxFeed.Graal.Net.Tests/Ipf/InstrumentProfileTests.cs @@ -0,0 +1,181 @@ +// +// Copyright © 2024 Devexperts LLC. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + +using DxFeed.Graal.Net.Ipf; + +namespace DxFeed.Graal.Net.Tests.Ipf; + +[TestFixture] +public class InstrumentProfileTests +{ + [Test] + public void Constructor_ShouldInitializeDefaultValues() + { + var profile = new InstrumentProfile(); + + Assert.Multiple(() => + { + Assert.That(profile.Type, Is.EqualTo(string.Empty)); + Assert.That(profile.Symbol, Is.EqualTo(string.Empty)); + Assert.That(profile.Description, Is.EqualTo(string.Empty)); + Assert.That(profile.LocalSymbol, Is.EqualTo(string.Empty)); + Assert.That(profile.LocalDescription, Is.EqualTo(string.Empty)); + Assert.That(profile.Country, Is.EqualTo(string.Empty)); + Assert.That(profile.OPOL, Is.EqualTo(string.Empty)); + Assert.That(profile.ExchangeData, Is.EqualTo(string.Empty)); + Assert.That(profile.Exchanges, Is.EqualTo(string.Empty)); + Assert.That(profile.Currency, Is.EqualTo(string.Empty)); + Assert.That(profile.BaseCurrency, Is.EqualTo(string.Empty)); + Assert.That(profile.CFI, Is.EqualTo(string.Empty)); + Assert.That(profile.ISIN, Is.EqualTo(string.Empty)); + Assert.That(profile.SEDOL, Is.EqualTo(string.Empty)); + Assert.That(profile.CUSIP, Is.EqualTo(string.Empty)); + Assert.That(profile.ICB, Is.EqualTo(0)); + Assert.That(profile.SIC, Is.EqualTo(0)); + Assert.That(profile.Multiplier, Is.EqualTo(0)); + Assert.That(profile.Product, Is.EqualTo(string.Empty)); + Assert.That(profile.Underlying, Is.EqualTo(string.Empty)); + Assert.That(profile.SPC, Is.EqualTo(0)); + Assert.That(profile.AdditionalUnderlyings, Is.EqualTo(string.Empty)); + Assert.That(profile.MMY, Is.EqualTo(string.Empty)); + Assert.That(profile.Expiration, Is.EqualTo(0)); + Assert.That(profile.LastTrade, Is.EqualTo(0)); + Assert.That(profile.Strike, Is.EqualTo(0)); + Assert.That(profile.OptionType, Is.EqualTo(string.Empty)); + Assert.That(profile.ExpirationStyle, Is.EqualTo(string.Empty)); + Assert.That(profile.SettlementStyle, Is.EqualTo(string.Empty)); + Assert.That(profile.PriceIncrements, Is.EqualTo(string.Empty)); + Assert.That(profile.TradingHours, Is.EqualTo(string.Empty)); + var customField = new List(); + Assert.That(profile.AddNonEmptyCustomFieldNames(customField), Is.False); + Assert.That(customField, Is.Empty); + }); + } + + [Test] + public void Properties_ShouldGetAndSetValues() => + AssertTestProfile(CreateTestProfile()); + + [Test] + public void AddNonEmptyCustomFieldNames_ShouldReturnTrueForNonEmptyField() + { + var profile = new InstrumentProfile(); + var actualFieldNames = new HashSet { "Field1", "Field2", "Field3" }; + foreach (var field in actualFieldNames) + { + profile.SetField(field, "Value"); + } + + var expectedFieldNames = new HashSet(); + Assert.Multiple(() => + { + Assert.That(profile.AddNonEmptyCustomFieldNames(expectedFieldNames), Is.True); + Assert.That(actualFieldNames.SetEquals(expectedFieldNames), Is.True); + }); + } + + [Test] + public void CopyConstructor_ShouldShouldCopyAllFields() + { + var profile = new InstrumentProfile(CreateTestProfile()); + AssertTestProfile(profile); + Assert.Multiple(() => + { + Assert.That(profile.GetHashCode(), Is.EqualTo(CreateTestProfile().GetHashCode())); + Assert.That(profile, Is.EqualTo(CreateTestProfile())); + }); + } + + [Test] + public void ToString_ShouldReturnExpectedFormat() + { + var profile = new InstrumentProfile { Type = "STOCK", Symbol = "GOOG" }; + var expectedString = "STOCK GOOG"; + + Assert.That(profile.ToString(), Is.EqualTo(expectedString)); + } + + private static InstrumentProfile CreateTestProfile() + { + var profile = new InstrumentProfile + { + Type = "FUTURE", + Symbol = "GOOG", + Description = "Google Inc.", + LocalSymbol = "Гугл", + LocalDescription = "Гугл Инк.", + Country = "US", + OPOL = "XNAS", + ExchangeData = "Data", + Exchanges = "XNYS", + Currency = "USD", + BaseCurrency = "USD", + CFI = "ESXXXX", + ISIN = "US38259P5089", + SEDOL = "2310967", + CUSIP = "38259P508", + ICB = 9535, + SIC = 7371, + Multiplier = 100, + Product = "/YG", + Underlying = "C", + SPC = 1, + AdditionalUnderlyings = "SE 50", + MMY = "202312", + Expiration = 20231231, + LastTrade = 20231230, + Strike = 1800, + OptionType = "STAN", + ExpirationStyle = "Quarterlys", + SettlementStyle = "Close", + PriceIncrements = "0.01 3; 0.05", + TradingHours = "NewYorkETH()" + }; + profile.SetField("Field1", "Test"); + profile.SetNumericField("Field2", 12.34); + profile.SetDateField("Field3", 1234); + return profile; + } + + private static void AssertTestProfile(InstrumentProfile profile) => + Assert.Multiple(() => + { + Assert.That(profile.Type, Is.EqualTo("FUTURE")); + Assert.That(profile.Symbol, Is.EqualTo("GOOG")); + Assert.That(profile.Description, Is.EqualTo("Google Inc.")); + Assert.That(profile.LocalSymbol, Is.EqualTo("Гугл")); + Assert.That(profile.LocalDescription, Is.EqualTo("Гугл Инк.")); + Assert.That(profile.Country, Is.EqualTo("US")); + Assert.That(profile.OPOL, Is.EqualTo("XNAS")); + Assert.That(profile.ExchangeData, Is.EqualTo("Data")); + Assert.That(profile.Exchanges, Is.EqualTo("XNYS")); + Assert.That(profile.Currency, Is.EqualTo("USD")); + Assert.That(profile.BaseCurrency, Is.EqualTo("USD")); + Assert.That(profile.CFI, Is.EqualTo("ESXXXX")); + Assert.That(profile.ISIN, Is.EqualTo("US38259P5089")); + Assert.That(profile.SEDOL, Is.EqualTo("2310967")); + Assert.That(profile.CUSIP, Is.EqualTo("38259P508")); + Assert.That(profile.ICB, Is.EqualTo(9535)); + Assert.That(profile.SIC, Is.EqualTo(7371)); + Assert.That(profile.Multiplier, Is.EqualTo(100)); + Assert.That(profile.Product, Is.EqualTo("/YG")); + Assert.That(profile.Underlying, Is.EqualTo("C")); + Assert.That(profile.SPC, Is.EqualTo(1)); + Assert.That(profile.AdditionalUnderlyings, Is.EqualTo("SE 50")); + Assert.That(profile.MMY, Is.EqualTo("202312")); + Assert.That(profile.Expiration, Is.EqualTo(20231231)); + Assert.That(profile.LastTrade, Is.EqualTo(20231230)); + Assert.That(profile.Strike, Is.EqualTo(1800)); + Assert.That(profile.OptionType, Is.EqualTo("STAN")); + Assert.That(profile.ExpirationStyle, Is.EqualTo("Quarterlys")); + Assert.That(profile.SettlementStyle, Is.EqualTo("Close")); + Assert.That(profile.PriceIncrements, Is.EqualTo("0.01 3; 0.05")); + Assert.That(profile.TradingHours, Is.EqualTo("NewYorkETH()")); + Assert.That(profile.GetField("Field1"), Is.EqualTo("Test")); + Assert.That(profile.GetNumericField("Field2"), Is.EqualTo(12.34)); + Assert.That(profile.GetDateField("Field3"), Is.EqualTo(1234)); + }); +} diff --git a/tests/DxFeed.Graal.Net.Tests/ipf.txt b/tests/DxFeed.Graal.Net.Tests/ipf.txt new file mode 100644 index 00000000..bf7bb96b --- /dev/null +++ b/tests/DxFeed.Graal.Net.Tests/ipf.txt @@ -0,0 +1,33 @@ +#STOCK::=TYPE,SYMBOL,DESCRIPTION,COUNTRY,OPOL,EXCHANGES,CURRENCY,CFI,ISIN,PRICE_INCREMENTS,TRADING_HOURS,AUTOCOMPLETE_WEIGHT,BITIP_GROSS_SETTLEMENT,BITIP_LAST_UPDATE,BITIP_MARKET,BITIP_MARKET_SEGMENT,BITIP_SYMBOL,MS_INDUSTRY_CODE,MS_NAICS,MS_SIC,NASDAQ_RAW_TYPE,OTC_CAVEAT_EMPTOR,OTC_PRIMARY_MARKET,OTC_SECURITY_TYPE,OTC_TIER_DESCRIPTION,SUBTYPES +STOCK,EREGL:TR,EREĞLİ DEMİR VE ÇELİK FABRİKALARI T.A.Ş.,TR,XIST,XIST,TRY,,TRAEREGL91G3,0.01 20; 0.02 50; 0.05 100; 0.1 250; 0.25 500; 0.5 1000; 1 2500; 2.5,BIST(name=BIST;tz=Asia/Istanbul;hd=TR;sd=TR;td=12345;de=+0000;0=10001800),,N,2024-06-28,MSPOT,Z,EREGL.E,,,,,,,,, +STOCK,TCELL:TR,TURKCELL İLETİŞİM HİZMETLERİ A.Ş.,TR,XIST,XIST,TRY,,TRATCELL91M1,0.01 20; 0.02 50; 0.05 100; 0.1 250; 0.25 500; 0.5 1000; 1 2500; 2.5,BIST(name=BIST;tz=Asia/Istanbul;hd=TR;sd=TR;td=12345;de=+0000;0=10001800),,N,2024-06-28,MSPOT,Z,TCELL.E,,,,,,,,, +STOCK,AXP,American Express Company Common Stock,US,XNYS,ARCX;BATS;BATY;EDGA;EDGX;EPRL;IEXG;LTSE;MEMX;XADF;XASE;XBOS;XCHI;XCIS;XNAS;XNYS;XPSX,USD,ESXXXX,,0.0001 1; 0.01,NewYorkETH(),2,,,,,,10360010,522220,6141,,,,,,Common Share; +STOCK,BASFY,BASF SE S/ADR by BASF SE,US,OOTC,OOTC,USD,,,0.0001 1; 0.01,OOTC(name=OTC Other;tz=America/New_York;hd=US;sd=US;td=12345;de=+0000;rt=0300;0=p08000930r09301600a16002005),,,,,,,10130010,,,,N,OP,ADR,QX, +STOCK,GARAN:TR,TÜRKİYE GARANTİ BANKASI A.Ş.,TR,XIST,XIST,TRY,,TRAGARAN91N1,0.01 20; 0.02 50; 0.05 100; 0.1 250; 0.25 500; 0.5 1000; 1 2500; 2.5,BIST(name=BIST;tz=Asia/Istanbul;hd=TR;sd=TR;td=12345;de=+0000;0=10001800),,N,2024-06-28,MSPOT,Z,GARAN.E,,,,,,,,, +STOCK,MSFT,Microsoft Corporation - Common Stock,US,XNAS,ARCX;BATS;BATY;EDGA;EDGX;IEXG;LTSE;MEMX;MPRL;XADF;XASE;XBOS;XCHI;XCIS;XNAS;XNYS;XPSX,USD,ESXXXX,,0.0001 1; 0.01,NewYorkETH(),3,,,,,,31110030,511210,7372,C.Z ,,,,,Common Share; +STOCK,CSCO,"Cisco Systems, Inc. - Common Stock",US,XNAS,ARCX;BATS;BATY;EDGA;EDGX;IEXG;LTSE;MEMX;MPRL;XADF;XASE;XBOS;XCHI;XCIS;XNAS;XNYS;XPSX,USD,ESXXXX,,0.0001 1; 0.01,NewYorkETH(),3,,,,,,31120010,334290,3577,C.Z ,,,,,Common Share; +STOCK,THYAO:TR,TÜRK HAVA YOLLARI A.O.,TR,XIST,XIST,TRY,,TRATHYAO91M5,0.01 20; 0.02 50; 0.05 100; 0.1 250; 0.25 500; 0.5 1000; 1 2500; 2.5,BIST(name=BIST;tz=Asia/Istanbul;hd=TR;sd=TR;td=12345;de=+0000;0=10001800),,N,2024-06-28,MSPOT,Z,THYAO.E,,,,,,,,, +STOCK,PLYZ,PLYZER TECHNOLOGIES INC by Plyzer Technologies Inc.,US,OOTC,OOTC,USD,,,0.0001 1; 0.01,OOTC(name=OTC Other;tz=America/New_York;hd=US;sd=US;td=12345;de=+0000;rt=0300;0=p08000930r09301600a16002005),,,,,,,31110030,541511,7379,,N,OP,CS,EM, +STOCK,TUPRS:TR,TÜPRAŞ-TÜRKİYE PETROL RAFİNERİLERİ A.Ş.,TR,XIST,XIST,TRY,,TRATUPRS91E8,0.01 20; 0.02 50; 0.05 100; 0.1 250; 0.25 500; 0.5 1000; 1 2500; 2.5,BIST(name=BIST;tz=Asia/Istanbul;hd=TR;sd=TR;td=12345;de=+0000;0=10001800),,N,2024-06-28,MSPOT,Z,TUPRS.E,,,,,,,,, +STOCK,AAPL,Apple Inc. - Common Stock,US,XNAS,ARCX;BATS;BATY;EDGA;EDGX;IEXG;LTSE;MEMX;MPRL;XADF;XASE;XBOS;XCHI;XCIS;XNAS;XNYS;XPSX,USD,ESXXXX,,0.0001 1; 0.01,NewYorkETH(),3,,,,,,31120030,334220,3571,C.Z ,,,,,Common Share; +STOCK,TTKOM:TR,TÜRK TELEKOMÜNİKASYON A.Ş.,TR,XIST,XIST,TRY,,TRETTLK00013,0.01 20; 0.02 50; 0.05 100; 0.1 250; 0.25 500; 0.5 1000; 1 2500; 2.5,BIST(name=BIST;tz=Asia/Istanbul;hd=TR;sd=TR;td=12345;de=+0000;0=10001800),,N,2024-06-28,MSPOT,Z,TTKOM.E,,,,,,,,, +STOCK,INTC,Intel Corporation - Common Stock,US,XNAS,ARCX;BATS;BATY;EDGA;EDGX;IEXG;LTSE;MEMX;MPRL;XADF;XASE;XBOS;XCHI;XCIS;XNAS;XNYS;XPSX,USD,ESXXXX,,0.0001 1; 0.01,NewYorkETH(),3,,,,,,31130020,334413,3674,C.Z ,,,,,Common Share; +STOCK,EONGY,E.ON SE S/ADR by E.ON SE,US,OOTC,OOTC,USD,,,0.0001 1; 0.01,OOTC(name=OTC Other;tz=America/New_York;hd=US;sd=US;td=12345;de=+0000;rt=0300;0=p08000930r09301600a16002005),,,,,,,20720040,,,,N,OP,ADR,PK, +STOCK,DANOY,DANONE S/ADR by Danone,US,OOTC,OOTC,USD,,,0.0001 1; 0.01,OOTC(name=OTC Other;tz=America/New_York;hd=US;sd=US;td=12345;de=+0000;rt=0300;0=p08000930r09301600a16002005),,,,,,,20525040,,,,N,OP,ADR,QX, +STOCK,GOOG,Alphabet Inc. - Class C Capital Stock,US,XNAS,ARCX;BATS;BATY;EDGA;EDGX;IEXG;LTSE;MEMX;MPRL;XADF;XASE;XBOS;XCHI;XCIS;XNAS;XNYS;XPSX,USD,ESXXXX,,0.0001 1; 0.01,NewYorkETH(),3,,,,,,30830010,519130,7375,C.Z ,,,,,Common Share; +STOCK,TUKAS:TR,TUKAŞ GIDA SANAYİ VE TİCARET A.Ş.,TR,XIST,XIST,TRY,,TRATUKAS91A3,0.01 20; 0.02 50; 0.05 100; 0.1 250; 0.25 500; 0.5 1000; 1 2500; 2.5,BIST(name=BIST;tz=Asia/Istanbul;hd=TR;sd=TR;td=12345;de=+0000;0=10001800),,N,2024-06-28,MSPOT,Z,TUKAS.E,,,,,,,,, +STOCK,META,"Meta Platforms, Inc. - Class A Common Stock",US,XNAS,ARCX;BATS;BATY;EDGA;EDGX;IEXG;LTSE;MEMX;MPRL;XADF;XASE;XBOS;XCHI;XCIS;XNAS;XNYS;XPSX,USD,ESXXXX,,0.0001 1; 0.01,NewYorkETH(),,,,,,,30830010,519190,7375,C.Z ,,,,,Common Share; +STOCK,NTRR,NEUTRA CORPORATION by Neutra Corp.,US,OOTC,OOTC,USD,,,0.0001 1; 0.01,OOTC(name=OTC Other;tz=America/New_York;hd=US;sd=US;td=12345;de=+0000;rt=0300;0=p08000930r09301600a16002005),,,,,,,20610010,325411,2833,,N,OP,CS,PK, +STOCK,PFE,"Pfizer, Inc. Common Stock",US,XNYS,ARCX;BATS;BATY;EDGA;EDGX;EPRL;IEXG;LTSE;MEMX;XADF;XASE;XBOS;XCHI;XCIS;XNAS;XNYS;XPSX,USD,ESXXXX,,0.0001 1; 0.01,NewYorkETH(),3,,,,,,20620010,325412,2834,,,,,,Common Share; +STOCK,AKBNK:TR,AKBANK T.A.Ş.,TR,XIST,XIST,TRY,,TRAAKBNK91N6,0.01 20; 0.02 50; 0.05 100; 0.1 250; 0.25 500; 0.5 1000; 1 2500; 2.5,BIST(name=BIST;tz=Asia/Istanbul;hd=TR;sd=TR;td=12345;de=+0000;0=10001800),,N,2024-06-28,MSPOT,Z,AKBNK.E,,,,,,,,, +STOCK,SUTI,"SUTIMCO INTL INC by SUTIMCo International, Inc.",US,OOTC,OOTC,USD,,,0.0001 1; 0.01,OOTC(name=OTC Other;tz=America/New_York;hd=US;sd=US;td=12345;de=+0000;rt=0300;0=p08000930r09301600a16002005),,,,,,,31120040,335929,3679,,N,OP,CS,EM, +STOCK,BAC,Bank of America Corporation Common Stock,US,XNYS,ARCX;BATS;BATY;EDGA;EDGX;EPRL;IEXG;LTSE;MEMX;XADF;XASE;XBOS;XCHI;XCIS;XNAS;XNYS;XPSX,USD,ESXXXX,,0.0001 1; 0.01,NewYorkETH(),3,,,,,,10320010,522110,6021,,,,,,Common Share; +STOCK,ADDYY,ADIDAS AG S/ADR by adidas AG,US,OOTC,OOTC,USD,,,0.0001 1; 0.01,OOTC(name=OTC Other;tz=America/New_York;hd=US;sd=US;td=12345;de=+0000;rt=0300;0=p08000930r09301600a16002005),,,,,,,10240030,,,,N,OP,ADR,QX, +STOCK,ARCLK:TR,ARÇELİK A.Ş.,TR,XIST,XIST,TRY,,TRAARCLK91H5,0.01 20; 0.02 50; 0.05 100; 0.1 250; 0.25 500; 0.5 1000; 1 2500; 2.5,BIST(name=BIST;tz=Asia/Istanbul;hd=TR;sd=TR;td=12345;de=+0000;0=10001800),,N,2024-06-28,MSPOT,Z,ARCLK.E,,,,,,,,, +STOCK,PGSUS:TR,PEGASUS HAVA TAŞIMACILIĞI A.Ş.,TR,XIST,XIST,TRY,,TREPEGS00016,0.01 20; 0.02 50; 0.05 100; 0.1 250; 0.25 500; 0.5 1000; 1 2500; 2.5,BIST(name=BIST;tz=Asia/Istanbul;hd=TR;sd=TR;td=12345;de=+0000;0=10001800),,N,2024-06-28,MSPOT,Z,PGSUS.E,,,,,,,,, +STOCK,XOM,Exxon Mobil Corporation Common Stock,US,XNYS,ARCX;BATS;BATY;EDGA;EDGX;EPRL;IEXG;LTSE;MEMX;XADF;XASE;XBOS;XCHI;XCIS;XNAS;XNYS;XPSX,USD,ESXXXX,,0.0001 1; 0.01,NewYorkETH(),3,,,,,,30910030,211120,1311,,,,,,Common Share; +STOCK,GOOGL,Alphabet Inc. - Class A Common Stock,US,XNAS,ARCX;BATS;BATY;EDGA;EDGX;IEXG;LTSE;MEMX;MPRL;XADF;XASE;XBOS;XCHI;XCIS;XNAS;XNYS;XPSX,USD,ESXXXX,,0.0001 1; 0.01,NewYorkETH(),3,,,,,,30830010,519130,7375,C.Z ,,,,,Common Share; +STOCK,IBM,International Business Machines Corporation Common Stock,US,XNYS,ARCX;BATS;BATY;EDGA;EDGX;EPRL;IEXG;LTSE;MEMX;XADF;XASE;XBOS;XCHI;XCIS;XNAS;XNYS;XPSX,USD,ESXXXX,,0.0001 1; 0.01,NewYorkETH(),3,,,,,,31110010,541512,7373,,,,,,Common Share; +STOCK,STWC,"STWC HOLDINGS INC by STWC Holdings, Inc.",US,OOTC,OOTC,USD,,,0.0001 1; 0.01,OOTC(name=OTC Other;tz=America/New_York;hd=US;sd=US;td=12345;de=+0000;rt=0300;0=p08000930r09301600a16002005),,,,,,,31020020,541618,8742,,N,OP,CS,EM, +STOCK,ABCE,"ABCO ENERGY INC by ABCO Energy, Inc.",US,OOTC,OOTC,USD,,,0.0001 1; 0.01,OOTC(name=OTC Other;tz=America/New_York;hd=US;sd=US;td=12345;de=+0000;rt=0300;0=p08000930r09301600a16002005),,,,,,,31130030,335110,3641,,N,OP,CS,EM, +##COMPLETE