From 846045baac22a74d226e65dfc185cd48ed74e72d Mon Sep 17 00:00:00 2001 From: Konstantin Ivaschenko Date: Thu, 13 Feb 2025 13:44:23 +0300 Subject: [PATCH] [MDAPI-171] [.NET] Optimize OptionChainsBuilder for performance in .NET compared to Java --- ReleaseNotes.txt | 2 + src/DxFeed.Graal.Net/DxFeed.Graal.Net.csproj | 4 +- src/DxFeed.Graal.Net/Ipf/InstrumentProfile.cs | 448 +++++-- .../Interop/InstrumentProfileMarshaler.cs | 169 +++ .../Native/Interop/JavaHandle.cs | 4 +- .../Ipf/InstrumentProfileCollectorHandle.cs | 9 +- .../Ipf/InstrumentProfileCustomFieldHandle.cs | 267 ++++ .../Native/Ipf/InstrumentProfileHandle.cs | 1106 ----------------- .../Native/Ipf/InstrumentProfileNative.cs | 47 + .../Ipf/InstrumentProfileReaderHandle.cs | 31 +- .../Ipf/IterableInstrumentProfileHandle.cs | 23 +- .../Native/Schedules/ScheduleHandle.cs | 80 +- .../Api/DXEndpointTest.cs | 10 +- .../Ipf/InstrumentProfileTests.cs | 10 +- .../Schedules/ScheduleTest.cs | 14 +- 15 files changed, 980 insertions(+), 1244 deletions(-) create mode 100644 src/DxFeed.Graal.Net/Native/Interop/InstrumentProfileMarshaler.cs create mode 100644 src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileCustomFieldHandle.cs delete mode 100644 src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileHandle.cs create mode 100644 src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileNative.cs diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt index 58c69b73..80bf0948 100644 --- a/ReleaseNotes.txt +++ b/ReleaseNotes.txt @@ -1,3 +1,5 @@ +* [MDAPI-171] [.NET] Optimize OptionChainsBuilder for performance in .NET compared to Java + ## Version 2.6.0 * [MDAPI-96] [.NET] Retrieve latest events from feed diff --git a/src/DxFeed.Graal.Net/DxFeed.Graal.Net.csproj b/src/DxFeed.Graal.Net/DxFeed.Graal.Net.csproj index 291a91cb..9392d0d4 100644 --- a/src/DxFeed.Graal.Net/DxFeed.Graal.Net.csproj +++ b/src/DxFeed.Graal.Net/DxFeed.Graal.Net.csproj @@ -4,6 +4,8 @@ true true SYSLIB1054 + true + true @@ -27,7 +29,7 @@ - + diff --git a/src/DxFeed.Graal.Net/Ipf/InstrumentProfile.cs b/src/DxFeed.Graal.Net/Ipf/InstrumentProfile.cs index d65d42f9..1a88d18d 100644 --- a/src/DxFeed.Graal.Net/Ipf/InstrumentProfile.cs +++ b/src/DxFeed.Graal.Net/Ipf/InstrumentProfile.cs @@ -1,13 +1,18 @@ // -// Copyright © 2022 Devexperts LLC. All rights reserved. +// Copyright © 2025 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 DxFeed.Graal.Net.Native.Ipf; using DxFeed.Graal.Net.Utils; +// Disable auto-property +#pragma warning disable S2292 + namespace DxFeed.Graal.Net.Ipf; /// @@ -17,13 +22,46 @@ namespace DxFeed.Graal.Net.Ipf; /// public class InstrumentProfile { - private readonly InstrumentProfileHandle handle; + private InstrumentProfileCustomFieldHandle customFieldHandle = InstrumentProfileCustomFieldHandle.Create(); + + 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; /// /// Initializes a new instance of the class. /// - public InstrumentProfile() => - handle = InstrumentProfileHandle.Create(); + public InstrumentProfile() + { + } /// /// Initializes a new instance of the class, @@ -36,11 +74,41 @@ 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) => - handle = InstrumentProfileHandle.Create(ip.GetHandle()); - - internal InstrumentProfile(InstrumentProfileHandle handle) => - this.handle = handle; + 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; + customFieldHandle = InstrumentProfileCustomFieldHandle.Create(ip.customFieldHandle); + } /// /// Gets or sets type of instrument. @@ -50,8 +118,8 @@ internal InstrumentProfile(InstrumentProfileHandle handle) => /// "STOCK", "FUTURE", "OPTION". public string Type { - get => handle.Type; - set => handle.Type = value; + get => type; + set => type = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -62,8 +130,8 @@ public string Type /// "GOOG", "/YGM9", ".ZYEAD". public string Symbol { - get => handle.Symbol; - set => handle.Symbol = value; + get => symbol; + set => symbol = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -73,8 +141,8 @@ public string Symbol /// "Google Inc.", "Mini Gold Futures,Jun-2009,ETH". public string Description { - get => handle.Description; - set => handle.Description = value; + get => description; + set => description = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -83,8 +151,8 @@ public string Description /// public string LocalSymbol { - get => handle.LocalSymbol; - set => handle.LocalSymbol = value; + get => localSymbol; + set => localSymbol = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -93,8 +161,8 @@ public string LocalSymbol /// public string LocalDescription { - get => handle.LocalDescription; - set => handle.LocalDescription = value; + get => localDescription; + set => localDescription = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -105,8 +173,8 @@ public string LocalDescription /// "US", "RU". public string Country { - get => handle.Country; - set => handle.Country = value; + get => country; + set => country = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -119,8 +187,8 @@ public string Country /// "XNAS", "RTSX". public string OPOL { - get => handle.OPOL; - set => handle.OPOL = value; + get => opol; + set => opol = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -129,8 +197,8 @@ public string OPOL /// public string ExchangeData { - get => handle.ExchangeData; - set => handle.ExchangeData = value; + get => exchangeData; + set => exchangeData = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -145,8 +213,8 @@ public string ExchangeData /// "ARCX;CBSX;XNAS;XNYS". public string Exchanges { - get => handle.Exchanges; - set => handle.Exchanges = value; + get => exchanges; + set => exchanges = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -157,8 +225,8 @@ public string Exchanges /// "USD", "RUB". public string Currency { - get => handle.Currency; - set => handle.Currency = value; + get => currency; + set => currency = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -167,8 +235,8 @@ public string Currency /// public string BaseCurrency { - get => handle.BaseCurrency; - set => handle.BaseCurrency = value; + get => baseCurrency; + set => baseCurrency = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -182,8 +250,8 @@ public string BaseCurrency /// "ESNTPB", "ESXXXX", "ES", "OPASPS". public string CFI { - get => handle.CFI; - set => handle.CFI = value; + get => cfi; + set => cfi = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -195,8 +263,8 @@ public string CFI /// "DE0007100000", "US38259P5089". public string ISIN { - get => handle.ISIN; - set => handle.ISIN = value; + get => isin; + set => isin = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -208,8 +276,8 @@ public string ISIN /// "2310967", "5766857". public string SEDOL { - get => handle.SEDOL; - set => handle.SEDOL = value; + get => sedol; + set => sedol = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -220,8 +288,8 @@ public string SEDOL /// "38259P508". public string CUSIP { - get => handle.CUSIP; - set => handle.CUSIP = value; + get => cusip; + set => cusip = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -233,8 +301,8 @@ public string CUSIP /// "9535". public int ICB { - get => handle.ICB; - set => handle.ICB = value; + get => icb; + set => icb = value; } /// @@ -246,8 +314,8 @@ public int ICB /// "7371". public int SIC { - get => handle.SIC; - set => handle.SIC = value; + get => sic; + set => sic = value; } /// @@ -256,8 +324,8 @@ public int SIC /// "100", "33.2". public double Multiplier { - get => handle.Multiplier; - set => handle.Multiplier = value; + get => multiplier; + set => multiplier = value; } /// @@ -266,8 +334,8 @@ public double Multiplier /// "/YG". public string Product { - get => handle.Product; - set => handle.Product = value; + get => product; + set => product = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -276,8 +344,8 @@ public string Product /// "C", "/YGM9". public string Underlying { - get => handle.Underlying; - set => handle.Underlying = value; + get => underlying; + set => underlying = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -286,8 +354,8 @@ public string Underlying /// "1", "100". public double SPC { - get => handle.SPC; - set => handle.SPC = value; + get => spc; + set => spc = value; } /// @@ -303,8 +371,8 @@ public double SPC /// "SE 50", "FIS 53; US$ 45.46". public string AdditionalUnderlyings { - get => handle.AdditionalUnderlyings; - set => handle.AdditionalUnderlyings = value; + get => additionalUnderlyings; + set => additionalUnderlyings = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -318,8 +386,8 @@ public string AdditionalUnderlyings /// public string MMY { - get => handle.MMY; - set => handle.MMY = value; + get => mmy; + set => mmy = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -328,8 +396,8 @@ public string MMY /// DayUtil.GetYearMonthDayByDayId(20090117). public int Expiration { - get => handle.Expiration; - set => handle.Expiration = value; + get => expiration; + set => expiration = value; } /// @@ -338,8 +406,8 @@ public int Expiration /// DayUtil.GetYearMonthDayByDayId(20090117). public int LastTrade { - get => handle.LastTrade; - set => handle.LastTrade = value; + get => lastTrade; + set => lastTrade = value; } /// @@ -348,8 +416,8 @@ public int LastTrade /// "80", "22.5". public double Strike { - get => handle.Strike; - set => handle.Strike = value; + get => strike; + set => strike = value; } /// @@ -367,8 +435,8 @@ public double Strike /// public string OptionType { - get => handle.OptionType; - set => handle.OptionType = value; + get => optionType; + set => optionType = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -376,8 +444,8 @@ public string OptionType /// public string ExpirationStyle { - get => handle.ExpirationStyle; - set => handle.ExpirationStyle = value; + get => expirationStyle; + set => expirationStyle = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -385,8 +453,8 @@ public string ExpirationStyle /// public string SettlementStyle { - get => handle.SettlementStyle; - set => handle.SettlementStyle = value; + get => settlementStyle; + set => settlementStyle = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -402,8 +470,8 @@ public string SettlementStyle /// "0.25", "0.01 3; 0.05". public string PriceIncrements { - get => handle.PriceIncrements; - set => handle.PriceIncrements = value; + get => priceIncrements; + set => priceIncrements = string.IsNullOrEmpty(value) ? string.Empty : value; } /// @@ -412,8 +480,14 @@ public string PriceIncrements /// public string TradingHours { - get => handle.TradingHours; - set => handle.TradingHours = value; + get => tradingHours; + set => tradingHours = string.IsNullOrEmpty(value) ? string.Empty : value; + } + + internal InstrumentProfileCustomFieldHandle CustomFields + { + get => customFieldHandle; + set => customFieldHandle = value; } /// @@ -422,7 +496,7 @@ public string TradingHours /// 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); + customFieldHandle.GetField(name); /// /// Sets the value of the field with the specified name. @@ -430,7 +504,7 @@ public string GetField(string name) => /// The name of the field. /// The value to set for the field. public void SetField(string name, string value) => - handle.SetField(name, value); + customFieldHandle.SetField(name, value); /// /// Gets the numeric value of the field with the specified name. @@ -438,7 +512,7 @@ public void SetField(string name, string value) => /// The name of the field. /// The numeric field value. public double GetNumericField(string name) => - handle.GetNumericField(name); + customFieldHandle.GetNumericField(name); /// /// Sets the numeric value of the field with the specified name. @@ -446,7 +520,7 @@ public double GetNumericField(string 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); + customFieldHandle.SetNumericField(name, value); /// /// Gets the day id value of the date field with the specified name. @@ -455,7 +529,7 @@ public void SetNumericField(string name, double value) => /// The name of the date field. /// The day id field value. public int GetDateField(string name) => - handle.GetDateField(name); + customFieldHandle.GetDateField(name); /// /// Sets the day id value of the date field with the specified name. @@ -464,7 +538,7 @@ public int GetDateField(string name) => /// 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); + customFieldHandle.SetDateField(name, value); /// /// Adds names of non-empty custom fields to the specified collection. @@ -476,30 +550,232 @@ public void SetDateField(string name, int value) => /// true if changed as a result of the call; otherwise, false. /// public bool AddNonEmptyCustomFieldNames(ICollection targetFieldNames) => - handle.AddNonEmptyCustomFieldNames(targetFieldNames); + customFieldHandle.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()); + public override bool Equals(object? obj) + { + if (ReferenceEquals(this, obj)) + { + return true; + } + + if (obj is not InstrumentProfile that) + { + return false; + } + + if (!type.Equals(that.type, StringComparison.Ordinal)) + { + return false; + } + + if (!symbol.Equals(that.symbol, StringComparison.Ordinal)) + { + return false; + } + + if (!description.Equals(that.description, StringComparison.Ordinal)) + { + return false; + } + + if (!localSymbol.Equals(that.localSymbol, StringComparison.Ordinal)) + { + return false; + } + + if (!localDescription.Equals(that.localDescription, StringComparison.Ordinal)) + { + return false; + } + + if (!country.Equals(that.country, StringComparison.Ordinal)) + { + return false; + } + + if (!opol.Equals(that.opol, StringComparison.Ordinal)) + { + return false; + } + + if (!exchangeData.Equals(that.exchangeData, StringComparison.Ordinal)) + { + return false; + } + + if (!exchanges.Equals(that.exchanges, StringComparison.Ordinal)) + { + return false; + } + + if (!currency.Equals(that.currency, StringComparison.Ordinal)) + { + return false; + } + + if (!baseCurrency.Equals(that.baseCurrency, StringComparison.Ordinal)) + { + return false; + } + + if (!cfi.Equals(that.cfi, StringComparison.Ordinal)) + { + return false; + } + + if (!isin.Equals(that.isin, StringComparison.Ordinal)) + { + return false; + } + + if (!sedol.Equals(that.sedol, StringComparison.Ordinal)) + { + return false; + } + + if (!cusip.Equals(that.cusip, StringComparison.Ordinal)) + { + return false; + } + + if (icb != that.icb) + { + return false; + } + + if (sic != that.sic) + { + return false; + } + + if (!multiplier.Equals(that.multiplier)) + { + return false; + } + + if (!product.Equals(that.product, StringComparison.Ordinal)) + { + return false; + } + + if (!underlying.Equals(that.underlying, StringComparison.Ordinal)) + { + return false; + } + + if (!spc.Equals(that.spc)) + { + return false; + } + + if (!additionalUnderlyings.Equals(that.additionalUnderlyings, StringComparison.Ordinal)) + { + return false; + } + + if (!mmy.Equals(that.mmy, StringComparison.Ordinal)) + { + return false; + } + + if (expiration != that.expiration) + { + return false; + } + + if (lastTrade != that.lastTrade) + { + return false; + } + + if (!strike.Equals(that.Strike)) + { + return false; + } + + if (!optionType.Equals(that.optionType, StringComparison.Ordinal)) + { + return false; + } + + if (!expirationStyle.Equals(that.expirationStyle, StringComparison.Ordinal)) + { + return false; + } + + if (!settlementStyle.Equals(that.settlementStyle, StringComparison.Ordinal)) + { + return false; + } + + if (!priceIncrements.Equals(that.priceIncrements, StringComparison.Ordinal)) + { + return false; + } + + if (!tradingHours.Equals(that.tradingHours, StringComparison.Ordinal)) + { + return false; + } + + return customFieldHandle.Equals(that.customFieldHandle); + } /// /// Returns a hash code value for this object. /// /// A hash code value for this object. - public override int GetHashCode() => - handle.GetHashCode(); + [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode", Justification = "Not immutable")] + public override int GetHashCode() + { + var result = type.GetHashCode(); + result = (31 * result) + symbol.GetHashCode(); + result = (31 * result) + description.GetHashCode(); + result = (31 * result) + localSymbol.GetHashCode(); + result = (31 * result) + localDescription.GetHashCode(); + result = (31 * result) + country.GetHashCode(); + result = (31 * result) + opol.GetHashCode(); + result = (31 * result) + exchangeData.GetHashCode(); + result = (31 * result) + exchanges.GetHashCode(); + result = (31 * result) + currency.GetHashCode(); + result = (31 * result) + baseCurrency.GetHashCode(); + result = (31 * result) + cfi.GetHashCode(); + result = (31 * result) + isin.GetHashCode(); + result = (31 * result) + sedol.GetHashCode(); + result = (31 * result) + cusip.GetHashCode(); + result = (31 * result) + icb; + result = (31 * result) + sic; + var temp = BitConverter.DoubleToInt64Bits(multiplier); + result = (31 * result) + (int)(temp ^ (long)((ulong)temp >> 32)); + result = (31 * result) + product.GetHashCode(); + result = (31 * result) + underlying.GetHashCode(); + temp = BitConverter.DoubleToInt64Bits(spc); + result = (31 * result) + (int)(temp ^ (long)((ulong)temp >> 32)); + result = (31 * result) + additionalUnderlyings.GetHashCode(); + result = (31 * result) + mmy.GetHashCode(); + result = (31 * result) + expiration; + result = (31 * result) + lastTrade; + temp = BitConverter.DoubleToInt64Bits(strike); + result = (31 * result) + (int)(temp ^ (long)((ulong)temp >> 32)); + result = (31 * result) + optionType.GetHashCode(); + result = (31 * result) + expirationStyle.GetHashCode(); + result = (31 * result) + settlementStyle.GetHashCode(); + result = (31 * result) + priceIncrements.GetHashCode(); + result = (31 * result) + tradingHours.GetHashCode(); + result = (31 * result) + customFieldHandle.GetHashCode(); + return result; + } /// /// Returns a string representation of the instrument profile. /// /// The string representation. public override string ToString() => - handle.ToString(); - - internal InstrumentProfileHandle GetHandle() => - handle; + $"{Type} {Symbol}"; } diff --git a/src/DxFeed.Graal.Net/Native/Interop/InstrumentProfileMarshaler.cs b/src/DxFeed.Graal.Net/Native/Interop/InstrumentProfileMarshaler.cs new file mode 100644 index 00000000..1109fa83 --- /dev/null +++ b/src/DxFeed.Graal.Net/Native/Interop/InstrumentProfileMarshaler.cs @@ -0,0 +1,169 @@ +// +// Copyright © 2025 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 DxFeed.Graal.Net.Native.Ipf; +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!, + CustomFields = profile->CustomFields != IntPtr.Zero ? + InstrumentProfileCustomFieldHandle.Clone(profile->CustomFields) : + InstrumentProfileCustomFieldHandle.Create(), + }; + } + + 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, + Hash = 0, + }; + 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)); + + private static class Import + { + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + EntryPoint = "dxfg_instrument_profile_free")] + public static extern int Release(nint thread, nint handle); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + EntryPoint = "dxfg_instrument_profile2_list_free")] + public static extern int ReleaseList(nint thread, nint handle); + } +} diff --git a/src/DxFeed.Graal.Net/Native/Interop/JavaHandle.cs b/src/DxFeed.Graal.Net/Native/Interop/JavaHandle.cs index 8bdddf3a..a6a7c325 100644 --- a/src/DxFeed.Graal.Net/Native/Interop/JavaHandle.cs +++ b/src/DxFeed.Graal.Net/Native/Interop/JavaHandle.cs @@ -1,5 +1,5 @@ // -// Copyright © 2024 Devexperts LLC. All rights reserved. +// Copyright © 2025 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/. // @@ -78,7 +78,7 @@ public override bool Equals(object? obj) return false; } - return Import.Equals(CurrentThread, this, that) != 0; + return ErrorCheck.SafeCall(Import.Equals(CurrentThread, this, that)) != 0; } public override string ToString() => diff --git a/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileCollectorHandle.cs b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileCollectorHandle.cs index 9a4baed5..3b2f13d7 100644 --- a/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileCollectorHandle.cs +++ b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileCollectorHandle.cs @@ -1,5 +1,5 @@ // -// Copyright © 2022 Devexperts LLC. All rights reserved. +// Copyright © 2025 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/. // @@ -26,7 +26,7 @@ public long GetLastUpdateTime() => ErrorCheck.SafeCall(NativeGetLastUpdateTime(CurrentThread, this)); public void UpdateInstrumentProfile(InstrumentProfile ip) => - ErrorCheck.SafeCall(NativeUpdateInstrumentProfile(CurrentThread, this, ip.GetHandle())); + ErrorCheck.SafeCall(NativeUpdateInstrumentProfile(CurrentThread, this, ip)); public IEnumerable View() { @@ -74,11 +74,12 @@ private static extern long NativeGetLastUpdateTime( ImportInfo.DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, - EntryPoint = "dxfg_InstrumentProfileCollector_updateInstrumentProfile")] + EntryPoint = "dxfg_InstrumentProfileCollector_updateInstrumentProfile2")] private static extern int NativeUpdateInstrumentProfile( nint thread, InstrumentProfileCollectorHandle collector, - InstrumentProfileHandle ip); + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(InstrumentProfileMarshaler))] + InstrumentProfile ip); [DllImport( ImportInfo.DllName, diff --git a/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileCustomFieldHandle.cs b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileCustomFieldHandle.cs new file mode 100644 index 00000000..b8c3ee5b --- /dev/null +++ b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileCustomFieldHandle.cs @@ -0,0 +1,267 @@ +// +// Copyright © 2025 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.Native.Interop; +using static DxFeed.Graal.Net.Native.ErrorHandling.ErrorCheck; + +namespace DxFeed.Graal.Net.Native.Ipf; + +internal class InstrumentProfileCustomFieldHandle : JavaHandle +{ + private static readonly StringMarshaler _marshaler = new(); + + public static InstrumentProfileCustomFieldHandle Create() + { + SafeCall(Import.New(CurrentThread, out var handle)); + return handle; + } + + public static InstrumentProfileCustomFieldHandle Create(InstrumentProfileCustomFieldHandle handle) + { + SafeCall(Import.New(CurrentThread, handle, out var newHandle)); + return newHandle; + } + + public static InstrumentProfileCustomFieldHandle Clone(IntPtr handle) + { + SafeCall(Import.CloneHandle(CurrentThread, handle, out var newHandle)); + return newHandle; + } + + public string GetField(string name) + { + SafeCall(Import.GetField(CurrentThread, this, name, out var value)); + return value; + } + + 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, out var value)); + return value; + } + + 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, out var value)); + return value; + } + + public void SetDateField(string name, int value) => + SafeCall(Import.SetDateField(CurrentThread, this, name, value)); + + public unsafe bool AddNonEmptyCustomFieldNames(ICollection targetFieldNames) + { + SafeCall(Import.GetNonEmptyFieldsNames(CurrentThread, this, out var ptr)); + var fields = ConvertToStringList(ptr); + + if (fields.Count == 0) + { + return false; + } + + if (targetFieldNames is ISet set) + { + var updated = false; + foreach (var field in fields) + { + if (set.Add(field)) + { + updated = true; + } + } + + return updated; + } + + foreach (var field in fields) + { + targetFieldNames.Add(field); + } + + return true; + } + + private static unsafe List ConvertToStringList(ListNative* handles) + { + try + { + var venues = new List(handles->Size); + for (var i = 0; i < handles->Size; i++) + { + var profile = (string)_marshaler.ConvertNativeToManaged((IntPtr)handles->Elements[i])!; + venues.Add(profile); + } + + return venues; + } + finally + { + SafeCall(Import.ReleaseList(CurrentThread, (IntPtr)handles)); + } + } + + private static class Import + { + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfileCustomFields_new")] + public static extern int New( + nint thread, + out InstrumentProfileCustomFieldHandle handle); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfileCustomFields_new3")] + public static extern int New( + nint thread, + InstrumentProfileCustomFieldHandle handle, + out InstrumentProfileCustomFieldHandle newHandle); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfileCustomFields_getField")] + public static extern int GetField( + nint thread, + InstrumentProfileCustomFieldHandle handle, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string name, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + out string value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfileCustomFields_setField")] + public static extern int SetField( + nint thread, + InstrumentProfileCustomFieldHandle handle, + [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_InstrumentProfileCustomFields_getNumericField")] + public static extern int GetNumericField( + nint thread, + InstrumentProfileCustomFieldHandle handle, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string name, + out double value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfileCustomFields_setNumericField")] + public static extern int SetNumericField( + nint thread, + InstrumentProfileCustomFieldHandle handle, + [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_InstrumentProfileCustomFields_getDateField")] + public static extern int GetDateField( + nint thread, + InstrumentProfileCustomFieldHandle handle, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] + string name, + out int value); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_InstrumentProfileCustomFields_setDateField")] + public static extern int SetDateField( + nint thread, + InstrumentProfileCustomFieldHandle handle, + [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_InstrumentProfileCustomFields_getNonEmptyFieldNames")] + public static extern unsafe int GetNonEmptyFieldsNames( + nint thread, + InstrumentProfileCustomFieldHandle handle, + out ListNative* fieldNames); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + ExactSpelling = true, + BestFitMapping = false, + ThrowOnUnmappableChar = true, + EntryPoint = "dxfg_JavaObjectHandler_clone")] + public static extern int CloneHandle( + nint thread, + IntPtr handle, + out InstrumentProfileCustomFieldHandle newHandle); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + EntryPoint = "dxfg_CList_String_release")] + public static extern int ReleaseList(nint thread, nint handle); + } +} diff --git a/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileHandle.cs b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileHandle.cs deleted file mode 100644 index a01423e3..00000000 --- a/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileHandle.cs +++ /dev/null @@ -1,1106 +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.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/InstrumentProfileNative.cs b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileNative.cs new file mode 100644 index 00000000..b871e3e1 --- /dev/null +++ b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileNative.cs @@ -0,0 +1,47 @@ +// +// Copyright © 2025 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.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, + IntPtr CustomFields, + int Hash); diff --git a/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileReaderHandle.cs b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileReaderHandle.cs index 0cb33c65..8ae8a4e1 100644 --- a/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileReaderHandle.cs +++ b/src/DxFeed.Graal.Net/Native/Ipf/InstrumentProfileReaderHandle.cs @@ -1,5 +1,5 @@ // -// Copyright © 2024 Devexperts LLC. All rights reserved. +// Copyright © 2025 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/. // @@ -19,6 +19,8 @@ namespace DxFeed.Graal.Net.Native.Ipf; [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "Created by marshaler")] internal sealed class InstrumentProfileReaderHandle : JavaHandle { + private static readonly InstrumentProfileMarshaler _marshaler = new(); + public static string? ResolveSourceUrl(string address) => SafeCall(Import.ResolveSourceUrl(CurrentThread, address)); @@ -33,14 +35,14 @@ public bool WasComplete() => public unsafe List ReadFromFile(string address, string? user, string? password) { - var ptr = SafeCall(Import.ReadFromFile(CurrentThread, this, address, user, password)); + SafeCall(Import.ReadFromFile(CurrentThread, this, address, user, password, out var ptr)); 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)); + SafeCall(Import.ReadFromFile(CurrentThread, this, address, tokenHandle, out var ptr)); return ConvertToProfiles(ptr); } @@ -48,10 +50,11 @@ private unsafe List ConvertToProfiles(ListNative* han { try { - var profiles = new List(); + var profiles = new List(handles->Size); for (var i = 0; i < handles->Size; i++) { - profiles.Add(new InstrumentProfile(new InstrumentProfileHandle((IntPtr)handles->Elements[i]))); + var profile = (InstrumentProfile)_marshaler.ConvertNativeToManaged((IntPtr)handles->Elements[i])!; + profiles.Add(profile); } return profiles; @@ -110,8 +113,8 @@ public static extern int WasComplete( ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true, - EntryPoint = "dxfg_InstrumentProfileReader_readFromFile2")] - public static extern unsafe ListNative* ReadFromFile( + EntryPoint = "dxfg_InstrumentProfileReader_readFromFile8")] + public static extern unsafe int ReadFromFile( nint thread, InstrumentProfileReaderHandle reader, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] @@ -119,7 +122,8 @@ public static extern int WasComplete( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] string? user, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] - string? password); + string? password, + out ListNative* profiles); [DllImport( ImportInfo.DllName, @@ -128,13 +132,14 @@ public static extern int WasComplete( ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true, - EntryPoint = "dxfg_InstrumentProfileReader_readFromFile3")] - public static extern unsafe ListNative* ReadFromFile( + EntryPoint = "dxfg_InstrumentProfileReader_readFromFile9")] + public static extern unsafe int ReadFromFile( nint thread, InstrumentProfileReaderHandle reader, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] string address, - AuthTokenHandle authToken); + AuthTokenHandle authToken, + out ListNative* profiles); [DllImport( ImportInfo.DllName, @@ -143,8 +148,8 @@ public static extern int WasComplete( ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true, - EntryPoint = "dxfg_CList_InstrumentProfile_wrapper_release")] - public static extern unsafe ListNative* ReleaseListWrapper( + EntryPoint = "dxfg_instrument_profile2_list_free")] + public static extern unsafe int ReleaseListWrapper( nint thread, ListNative* list); } diff --git a/src/DxFeed.Graal.Net/Native/Ipf/IterableInstrumentProfileHandle.cs b/src/DxFeed.Graal.Net/Native/Ipf/IterableInstrumentProfileHandle.cs index 35df6acd..dc4b47bc 100644 --- a/src/DxFeed.Graal.Net/Native/Ipf/IterableInstrumentProfileHandle.cs +++ b/src/DxFeed.Graal.Net/Native/Ipf/IterableInstrumentProfileHandle.cs @@ -1,5 +1,5 @@ // -// Copyright © 2022 Devexperts LLC. All rights reserved. +// Copyright © 2025 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/. // @@ -15,6 +15,8 @@ namespace DxFeed.Graal.Net.Native.Ipf; internal sealed class IterableInstrumentProfileHandle : JavaHandle { + private static readonly InstrumentProfileMarshaler _marshaler = new(); + public IterableInstrumentProfileHandle() { } @@ -40,8 +42,16 @@ public bool HasNext() => public InstrumentProfile? Next() { - var i = NativeNext(CurrentThread, this); - return i != null ? new InstrumentProfile(i) : null; + var ptr = IntPtr.Zero; + try + { + ErrorCheck.SafeCall(NativeNext(CurrentThread, this, out ptr)); + return (InstrumentProfile?)_marshaler.ConvertNativeToManaged(ptr); + } + finally + { + _marshaler.CleanUpFromNative(ptr); + } } [DllImport( @@ -63,8 +73,9 @@ private static extern int NativeHasNext( ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true, - EntryPoint = "dxfg_Iterable_InstrumentProfile_next")] - private static extern InstrumentProfileHandle? NativeNext( + EntryPoint = "dxfg_Iterable_InstrumentProfile_next2")] + private static extern int NativeNext( nint thread, - IterableInstrumentProfileHandle iterable); + IterableInstrumentProfileHandle handle, + out IntPtr profile); } diff --git a/src/DxFeed.Graal.Net/Native/Schedules/ScheduleHandle.cs b/src/DxFeed.Graal.Net/Native/Schedules/ScheduleHandle.cs index 419f86b0..01911603 100644 --- a/src/DxFeed.Graal.Net/Native/Schedules/ScheduleHandle.cs +++ b/src/DxFeed.Graal.Net/Native/Schedules/ScheduleHandle.cs @@ -1,15 +1,15 @@ // -// Copyright © 2024 Devexperts LLC. All rights reserved. +// Copyright © 2025 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.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,17 +17,28 @@ namespace DxFeed.Graal.Net.Native.Schedules; [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global", Justification = "Created by marshaler")] internal sealed class ScheduleHandle : JavaHandle { - public static ScheduleHandle GetInstance(InstrumentProfile profile) => - SafeCall(Import.GetInstance(CurrentThread, profile.GetHandle())); + private static readonly StringMarshaler _marshaler = new(); + + public static ScheduleHandle GetInstance(InstrumentProfile profile) + { + SafeCall(Import.GetInstance(CurrentThread, profile, out var scheduleHandle)); + return scheduleHandle; + } public static ScheduleHandle GetInstance(string scheduleDefinition) => SafeCall(Import.GetInstance(CurrentThread, scheduleDefinition)); - public static ScheduleHandle GetInstance(InstrumentProfile profile, string venue) => - SafeCall(Import.GetInstance(CurrentThread, profile.GetHandle(), venue)); + public static ScheduleHandle GetInstance(InstrumentProfile profile, string venue) + { + SafeCall(Import.GetInstance(CurrentThread, profile, venue, out var scheduleHandle)); + return scheduleHandle; + } - public static List GetTradingVenues(InstrumentProfile profile) => - SafeCall(Import.GetTradingVenues(CurrentThread, profile.GetHandle())); + public static unsafe List GetTradingVenues(InstrumentProfile profile) + { + SafeCall(Import.GetTradingVenues(CurrentThread, profile, out var venues)); + return ConvertToStringList(venues); + } public static void DownloadDefaults(string downloadConfig) => SafeCall(Import.DownloadDefaults(CurrentThread, downloadConfig)); @@ -65,6 +76,25 @@ public string GetName() => public string GetTimeZone() => SafeCall(Import.GetTimeZone(CurrentThread, this)); + private static unsafe List ConvertToStringList(ListNative* handles) + { + try + { + var venues = new List(handles->Size); + for (var i = 0; i < handles->Size; i++) + { + var profile = (string)_marshaler.ConvertNativeToManaged((IntPtr)handles->Elements[i])!; + venues.Add(profile); + } + + return venues; + } + finally + { + SafeCall(Import.ReleaseList(CurrentThread, (IntPtr)handles)); + } + } + private static class Import { [DllImport( @@ -74,10 +104,12 @@ private static class Import ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true, - EntryPoint = "dxfg_Schedule_getInstance")] - public static extern ScheduleHandle GetInstance( + EntryPoint = "dxfg_Schedule_getInstance4")] + public static extern int GetInstance( nint thread, - InstrumentProfileHandle profile); + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(InstrumentProfileMarshaler))] + InstrumentProfile profile, + out ScheduleHandle handle); [DllImport( ImportInfo.DllName, @@ -99,12 +131,14 @@ public static extern ScheduleHandle GetInstance( ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true, - EntryPoint = "dxfg_Schedule_getInstance3")] - public static extern ScheduleHandle GetInstance( + EntryPoint = "dxfg_Schedule_getInstance5")] + public static extern int GetInstance( nint thread, - InstrumentProfileHandle profile, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(InstrumentProfileMarshaler))] + InstrumentProfile profile, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] - string venue); + string venue, + out ScheduleHandle handle); [DllImport( ImportInfo.DllName, @@ -113,11 +147,12 @@ public static extern ScheduleHandle GetInstance( ExactSpelling = true, BestFitMapping = false, ThrowOnUnmappableChar = true, - EntryPoint = "dxfg_Schedule_getTradingVenues")] - [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ListMarshaler))] - public static extern List GetTradingVenues( + EntryPoint = "dxfg_Schedule_getTradingVenues2")] + public static extern unsafe int GetTradingVenues( nint thread, - InstrumentProfileHandle profile); + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(InstrumentProfileMarshaler))] + InstrumentProfile profile, + out ListNative* handle); [DllImport( ImportInfo.DllName, @@ -232,5 +267,12 @@ public static extern DayHandle GetDayByYearMonthDay( EntryPoint = "dxfg_Schedule_getTimeZone")] [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringMarshaler))] public static extern string GetTimeZone(nint thread, ScheduleHandle schedule); + + [DllImport( + ImportInfo.DllName, + CallingConvention = CallingConvention.Cdecl, + CharSet = CharSet.Ansi, + EntryPoint = "dxfg_CList_String_release")] + public static extern int ReleaseList(nint thread, nint handle); } } diff --git a/tests/DxFeed.Graal.Net.Tests/Api/DXEndpointTest.cs b/tests/DxFeed.Graal.Net.Tests/Api/DXEndpointTest.cs index eae32a76..dcae93da 100644 --- a/tests/DxFeed.Graal.Net.Tests/Api/DXEndpointTest.cs +++ b/tests/DxFeed.Graal.Net.Tests/Api/DXEndpointTest.cs @@ -1,10 +1,9 @@ // -// Copyright © 2022 Devexperts LLC. All rights reserved. +// Copyright © 2025 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.Net.NetworkInformation; using DxFeed.Graal.Net.Api; using DxFeed.Graal.Net.Api.Osub; using DxFeed.Graal.Net.Events; @@ -18,12 +17,15 @@ namespace DxFeed.Graal.Net.Tests.Api; [TestFixture] public class DXEndpointTest { + private static readonly Random rnd = new(); + [Test] public void ConnectToLocalPublisher() { + var port = rnd.Next(48658, 49150); var countdownEvent = new CountdownEvent(1); - var pub = Create(Publisher).Connect(":5679"); + var pub = Create(Publisher).Connect($":{port}"); var feed = Create(Feed); feed.AddStateChangeListener((_, newState) => { @@ -32,7 +34,7 @@ public void ConnectToLocalPublisher() countdownEvent.Signal(); } }); - feed.Connect("localhost:5679"); + feed.Connect($"localhost:{port}"); Assert.That(countdownEvent.Wait(new TimeSpan(0, 0, 3)), Is.True); pub.Close(); feed.Close(); diff --git a/tests/DxFeed.Graal.Net.Tests/Ipf/InstrumentProfileTests.cs b/tests/DxFeed.Graal.Net.Tests/Ipf/InstrumentProfileTests.cs index d30fb7d5..28b9d6c5 100644 --- a/tests/DxFeed.Graal.Net.Tests/Ipf/InstrumentProfileTests.cs +++ b/tests/DxFeed.Graal.Net.Tests/Ipf/InstrumentProfileTests.cs @@ -1,5 +1,5 @@ // -// Copyright © 2024 Devexperts LLC. All rights reserved. +// Copyright © 2025 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/. // @@ -74,6 +74,7 @@ public void AddNonEmptyCustomFieldNames_ShouldReturnTrueForNonEmptyField() { Assert.That(profile.AddNonEmptyCustomFieldNames(expectedFieldNames), Is.True); Assert.That(actualFieldNames.SetEquals(expectedFieldNames), Is.True); + Assert.That(profile.AddNonEmptyCustomFieldNames(expectedFieldNames), Is.False); }); } @@ -87,6 +88,13 @@ public void CopyConstructor_ShouldShouldCopyAllFields() Assert.That(profile.GetHashCode(), Is.EqualTo(CreateTestProfile().GetHashCode())); Assert.That(profile, Is.EqualTo(CreateTestProfile())); }); + var profile1 = new InstrumentProfile(profile); + profile.SetField("Field1", "NewValue"); + Assert.Multiple(() => + { + Assert.That(profile.GetField("Field1"), Is.EqualTo("NewValue")); + Assert.That(profile1.GetField("Field1"), Is.EqualTo("Test")); + }); } [Test] diff --git a/tests/DxFeed.Graal.Net.Tests/Schedules/ScheduleTest.cs b/tests/DxFeed.Graal.Net.Tests/Schedules/ScheduleTest.cs index 4c730afe..997226df 100644 --- a/tests/DxFeed.Graal.Net.Tests/Schedules/ScheduleTest.cs +++ b/tests/DxFeed.Graal.Net.Tests/Schedules/ScheduleTest.cs @@ -1,5 +1,5 @@ // -// Copyright © 2024 Devexperts LLC. All rights reserved. +// Copyright © 2025 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/. // @@ -40,7 +40,7 @@ public void Day_ShouldReturnsNullValueForInvalidDay() { var profiles = new InstrumentProfileReader().ReadFromFile(TestIpf); foreach (var profile in profiles) { - var schedule = Schedule.GetInstance(profile); + var schedule = Schedule.GetInstance(profile.TradingHours); var day = schedule.GetDayByYearMonthDay(01011950); Assert.Multiple(() => { @@ -53,4 +53,14 @@ public void Day_ShouldReturnsNullValueForInvalidDay() }); } } + + [Test] + public void Schedule_ShouldReturnCorrectVenues() + { + var profiles = new InstrumentProfileReader().ReadFromFile(TestIpf); + var aapl = profiles.Find(profile => profile.Symbol.Equals("AAPL", StringComparison.Ordinal)); + var venues = Schedule.GetTradingVenues(aapl ?? throw new InvalidOperationException()); + Assert.That(venues, Has.Count.EqualTo(1)); + Assert.That(venues[0], Is.EqualTo("NewYorkETH")); + } }