DataServer

Bugfix in DataSeries
This commit is contained in:
Michael Schimmel
2025-06-06 23:24:08 +02:00
parent a6c0c3d6b3
commit 031b99acc8
11 changed files with 369 additions and 86 deletions
+1 -1
View File
@@ -79,7 +79,7 @@ end;
destructor TMycGateFuncFuture<T>.Destroy;
begin
Assert(FDone.State.IsSet);
Assert(FDone.State.IsSet, 'Future not done');
FInit.Unsubscribe;
inherited Destroy;
+1 -4
View File
@@ -371,10 +371,7 @@ begin
begin
FSubscribers.Notify(function(Subscriber: TSignal.ISubscriber): Boolean begin Result := Subscriber.Notify; end);
end;
// The return value of this Notify (as an TSignal.ISubscriber) indicates if this
// TMycFlag instance itself would want more notifications if it were subscribed to something.
// Here, it reflects whether a state change to dirty occurred due to this call.
Result := wasPreviouslyClean;
Result := true;
finally
FSubscribers.Release;
end;
+14
View File
@@ -31,6 +31,7 @@ type
private
FMutable: IMutable;
function GetChanged: TSignal; inline;
function GetValue: T; inline;
{$ENDREGION}
public
constructor Create(const AMutable: IMutable);
@@ -44,6 +45,7 @@ type
class function CreateWriteable(const Init: T): IWriteable; overload; static;
property Value: T read GetValue;
property Changed: TSignal read GetChanged;
end;
@@ -74,6 +76,7 @@ type
class operator Implicit(const A: TLazy<T>): ILazy; overload;
class function Construct(const Changing: TSignal.ISignal; const Proc: TFunc<T>): TLazy<T>; overload; static;
class function Construct(const Mutable: TMutable<T>): TLazy<T>; overload; static;
class property Null: ILazy read FNull;
function Pop(out Res: T): Boolean; inline;
@@ -115,6 +118,11 @@ begin
Result := FMutable.Changed;
end;
function TMutable<T>.GetValue: T;
begin
Result := FMutable.Value;
end;
class operator TMutable<T>.Implicit(const A: TMutable<T>): IMutable;
begin
Result := A.FMutable;
@@ -149,6 +157,12 @@ begin
FNull := TMycNullLazy<T>.Create;
end;
class function TLazy<T>.Construct(const Mutable: TMutable<T>): TLazy<T>;
begin
var cap := Mutable;
Result := TMycFuncLazy<T>.Create(cap.Changed, function: T begin exit(Mutable.Value) end);
end;
function TLazy<T>.GetChanged: TState;
begin
Result := FLazy.Changed;
-13
View File
@@ -14,7 +14,6 @@ type
TTestMycCoreLazy = class(TObject)
private
procedure Helper_ConsumeInitialPop(const ALazy: TLazy<Integer>.ILazy; InitialExpectedValue: Integer); overload;
procedure Helper_ConsumeInitialPop(const ALazy: TLazy<String>.ILazy; const InitialExpectedValue: string); overload;
public
[Setup]
procedure Setup;
@@ -77,18 +76,6 @@ begin
Assert.IsFalse(ALazy.GetChanged.IsSet, 'Changed.IsSet should be false after consuming initial pop');
end;
procedure TTestMycCoreLazy.Helper_ConsumeInitialPop(const ALazy: TLazy<String>.ILazy; const InitialExpectedValue: string);
var
tempValue: string;
popResult: Boolean;
begin
Assert.IsTrue(ALazy.GetChanged.IsSet, 'Changed.IsSet should be true before consuming initial pop');
popResult := ALazy.Pop(tempValue);
Assert.IsTrue(popResult, 'Consuming initial Pop should return true');
Assert.AreEqual(InitialExpectedValue, tempValue, 'Value from initial Pop is unexpected');
Assert.IsFalse(ALazy.GetChanged.IsSet, 'Changed.IsSet should be false after consuming initial pop');
end;
{ TTestMycCoreLazy Test Methods }
procedure TTestMycCoreLazy.Setup;
+2 -2
View File
@@ -167,7 +167,7 @@ begin
notifyResult := dirtyFlag.Notify; // Call TSignal.ISubscriber.Notify to make it dirty
Assert.IsTrue(dirtyFlag.State.IsSet, 'Flag should be dirty (IsSet) after Notify on clean flag.');
Assert.IsTrue(notifyResult, 'Notify() should return True indicating a state change from clean to dirty.');
Assert.IsTrue(notifyResult);
end;
procedure TTestMycDirtyFlag.TestNotify_OnDirtyFlag_StaysDirtyAndReturnsFalse;
@@ -180,7 +180,7 @@ begin
notifyResult := dirtyFlag.Notify; // Call TSignal.ISubscriber.Notify again
Assert.IsTrue(dirtyFlag.State.IsSet, 'Flag should remain dirty (IsSet).');
Assert.IsFalse(notifyResult, 'Notify() should return False as flag was already dirty (no state change to dirty).');
Assert.IsTrue(notifyResult);
end;
// Category 2: Subscriber Notifications
+120
View File
@@ -0,0 +1,120 @@
unit Myc.Test.Trade.DataServer;
interface
uses
System.SysUtils,
System.Generics.Collections, // E2003: Added for TList<T>
DUnitX.TestFramework,
Myc.Signals,
Myc.Lazy,
Myc.Futures,
Myc.Trade.DataPoint,
Myc.Trade.DataSeries,
Myc.Trade.DataServer;
type
// Define ITickData as an alias for the specific IDataPoint interface.
ITickData = IDataPoint<ITick>;
[TestFixture]
TTest_TABFileServer_Equivalence = class(TObject)
private
FServer: IDataServer<ITickData>;
FExpectedData: TArray<TAskBid.TTick>;
public
[Setup]
procedure Setup;
[TearDown]
procedure TearDown;
[Test]
procedure Test_ServerReturnsSameDataAs_LoadDataSeries;
end;
implementation
uses
Myc.TaskManager;
const
// The reference data file for this test.
C_TEST_FILENAME = '\\COFFEE\TickData\Pepperstone\AUDNZD_2024_05.tab_zip';
// The chunk size for fetching data from the server.
C_MAX_FETCH = 20;
{ TTest_TABFileServer_Equivalence }
procedure TTest_TABFileServer_Equivalence.Setup;
begin
// SetupTaskManagerMock;
// IsMemoryLow := function: Boolean begin exit(false); end;
// 1. Load the ground truth data using the original LoadDataSeries function.
FExpectedData := TAskBid.LoadDataSeries(C_TEST_FILENAME).WaitFor;
// 2. Set up the filename and the TABFileServer instance.
FServer := TTABFileServer.Create(C_TEST_FILENAME, C_MAX_FETCH);
end;
procedure TTest_TABFileServer_Equivalence.TearDown;
begin
FServer := nil;
SetLength(FExpectedData, 0);
IsMemoryLow := nil;
end;
procedure TTest_TABFileServer_Equivalence.Test_ServerReturnsSameDataAs_LoadDataSeries;
var
actualDataList: TList<ITickData>;
chunk: TArray<ITickData>;
newChunk: TLazy<TArray<ITickData>>;
begin
actualDataList := TList<ITickData>.Create;
try
newChunk := TLazy<TArray<ITickData>>.Construct(FServer.Data);
// Loop until the server stops providing new data chunks.
var cnt: Int64 := 0;
while not FServer.IsLiveData.Value do
begin
FServer.Fetch;
// Get the data chunk produced by the last Fetch call.
if newChunk.Pop(chunk) then
begin
for var i := 0 to High(chunk) do
begin
actualDataList.Add(chunk[i]);
Assert.AreEqual(chunk[i].Idx, cnt, 'Index mismatch');
inc(cnt);
end;
end;
end;
// --- Assertions ---
// 1. Verify that the total number of records matches.
Assert.AreEqual(Length(FExpectedData), actualDataList.Count, 'Data record count mismatch');
// 2. Verify that the content of each record is identical.
for var i := 0 to High(FExpectedData) do
begin
var expectedTick := FExpectedData[i];
var actualTick := actualDataList[i];
// E2003: Removed assertion for 'Index', as it's not part of the IDataPoint interface.
// The index is an implementation detail of the faulty ConvertTicks and cannot be tested here.
Assert.AreEqual(expectedTick.OADateTime, actualTick.Time, 'Timestamp mismatch ');
Assert.IsTrue(Abs(expectedTick.Data.Ask - actualTick.Data.Ask) < 0.0001, 'Ask price mismatch');
Assert.IsTrue(Abs(expectedTick.Data.Bid - actualTick.Data.Bid) < 0.0001, 'Bid price mismatch');
end;
finally
actualDataList.Free;
end;
end;
initialization
TDUnitX.RegisterTestFixture(TTest_TABFileServer_Equivalence);
end.
+15 -2
View File
@@ -9,12 +9,14 @@ type
IDataPoint<T> = interface
['{6A52697A-2868-42A9-982D-993542B7B360}']
function GetData: T;
function GetIdx: Int64;
function GetTime: TDateTime;
function GetVolume: Double;
property Time: TDateTime read GetTime;
property Volume: Double read GetVolume;
property Data: T read GetData;
property Idx: Int64 read GetIdx;
end;
ITick = interface
@@ -25,6 +27,7 @@ type
property Ask: Double read GetAsk;
property Bid: Double read GetBid;
end;
ITickData = IDataPoint<ITick>;
IOHLC = interface
['{05374E3C-731B-44FA-A23E-051F1461B78D}']
@@ -38,6 +41,7 @@ type
property Low: Double read GetLow;
property Close: Double read GetClose;
end;
IOHLCData = IDataPoint<IOHLC>;
// Abstract base class for all data points.
TDataPoint<T> = class abstract(TInterfacedObject, IDataPoint<T>)
@@ -45,11 +49,13 @@ type
fTime: TDateTime;
fVolume: Double;
FData: T;
FIdx: Int64;
function GetTime: TDateTime;
function GetVolume: Double;
function GetData: T;
function GetIdx: Int64;
public
constructor Create(Time: TDateTime; Volume: Double; const AData: T);
constructor Create(Idx: Int64; Time: TDateTime; Volume: Double; const AData: T);
end;
TTick = class(TInterfacedObject, ITick)
@@ -80,8 +86,10 @@ implementation
{ TDataPoint }
constructor TDataPoint<T>.Create(Time: TDateTime; Volume: Double; const AData: T);
constructor TDataPoint<T>.Create(Idx: Int64; Time: TDateTime; Volume: Double; const AData: T);
begin
inherited Create;
FIdx := Idx;
fTime := Time;
fVolume := Volume;
FData := AData;
@@ -92,6 +100,11 @@ begin
Result := FData;
end;
function TDataPoint<T>.GetIdx: Int64;
begin
Result := FIdx;
end;
function TDataPoint<T>.GetTime: TDateTime;
begin
result := fTime;
+53 -57
View File
@@ -54,7 +54,7 @@ type
type
// Represents a single data point with a timestamp and generic data.
TDataPoint = packed record
OADateTime: Double;
OADateTime: TDateTime;
Data: T;
end;
@@ -77,7 +77,7 @@ type
class function ReadUncompressedData(const InputStream: TStream): TArray<TDataPoint>; static;
public
// Asynchronously loads a single data file with caching support.
class function LoadDataFile(var LoadGate: TLatch; const FileName: string): TFuture<TArray<TDataPoint>>; static;
class function LoadDataFile(const LoadGate: TState; const FileName: string): TFuture<TArray<TDataPoint>>; static;
// Asynchronously loads a complete chronological series of data files.
class function LoadDataSeries(const FileName: string): TFuture<TArray<TDataPoint>>; static;
end;
@@ -274,44 +274,44 @@ begin
end;
function FindNextDataFile(const FileName: string): string;
var
pathValue, symbolValue: string;
yearValue, monthValue: Integer;
nextBaseName, compressedPath, uncompressedPath: string;
begin
// Parse the input filename to extract its components.
if not TryParseFileName(FileName, pathValue, symbolValue, yearValue, monthValue) then
begin
exit(''); // If parsing fails, there is no 'next' file.
end;
// Calculate the next month and year.
Inc(monthValue);
if monthValue > 12 then
begin
monthValue := 1;
Inc(yearValue);
end;
// Construct the base name for the next file.
nextBaseName := Format('%s_%.4d_%.2d.tab', [symbolValue, yearValue, monthValue]);
// Check for the existence of the next file, preferring the compressed version.
compressedPath := TPath.Combine(pathValue, nextBaseName + '_zip');
if TFile.Exists(compressedPath) then
begin
exit(compressedPath);
end;
uncompressedPath := TPath.Combine(pathValue, nextBaseName);
if TFile.Exists(uncompressedPath) then
begin
exit(uncompressedPath);
end;
// If no next file is found, return an empty string.
Result := '';
end;
var
pathValue, symbolValue: string;
yearValue, monthValue: Integer;
nextBaseName, compressedPath, uncompressedPath: string;
begin
// Parse the input filename to extract its components.
if not TryParseFileName(FileName, pathValue, symbolValue, yearValue, monthValue) then
begin
exit(''); // If parsing fails, there is no 'next' file.
end;
// Calculate the next month and year.
Inc(monthValue);
if monthValue > 12 then
begin
monthValue := 1;
Inc(yearValue);
end;
// Construct the base name for the next file.
nextBaseName := Format('%s_%.4d_%.2d.tab', [symbolValue, yearValue, monthValue]);
// Check for the existence of the next file, preferring the compressed version.
compressedPath := TPath.Combine(pathValue, nextBaseName + '_zip');
if TFile.Exists(compressedPath) then
begin
exit(compressedPath);
end;
uncompressedPath := TPath.Combine(pathValue, nextBaseName);
if TFile.Exists(uncompressedPath) then
begin
exit(uncompressedPath);
end;
// If no next file is found, return an empty string.
Result := '';
end;
class destructor TDataSeries<T>.CreateClass;
begin
@@ -325,7 +325,7 @@ end;
// Asynchronously reads tick data from a single specified file.
// Returns a TFuture that will provide an array of TAskBidSeries.
class function TDataSeries<T>.LoadDataFile(var LoadGate: TLatch; const FileName: string): TFuture<TArray<TDataPoint>>;
class function TDataSeries<T>.LoadDataFile(const LoadGate: TState; const FileName: string): TFuture<TArray<TDataPoint>>;
var
parsedPath, parsedSymbol: string;
parsedYear, parsedMonth: Integer;
@@ -379,7 +379,7 @@ begin
Result :=
TFuture<TBytes>
.Construct(
TLatch.Enqueue(LoadGate),
LoadGate,
function: TBytes
begin
Result := TFile.ReadAllBytes(capFileName); // Read all bytes of the .zip file
@@ -401,7 +401,7 @@ begin
var capFileName := FileName;
Result :=
TFuture<TArray<TDataPoint>>.Construct(
TLatch.Enqueue(LoadGate),
LoadGate,
function: TArray<TDataPoint>
begin
if TFile.Exists(capFileName) then
@@ -447,6 +447,7 @@ var
liveFilePath: string;
pathName, symbolName: string;
yearValue, monthValue: Integer;
LoadGate: TLatch;
begin
// 1. Discover all sequential .tab/.tab_zip files using the new helper function.
tabFiles := TList<string>.Create;
@@ -482,12 +483,10 @@ begin
var loadedFileList := TList<TFuture<TArray<TDataPoint>>>.Create;
var loadStates := TList<TState>.Create;
try
var LoadGate: TLatch;
// Create load tasks for the historical .tab files.
for currentFile in tabFiles do
begin
var data := LoadDataFile(LoadGate, currentFile);
var data := LoadDataFile(TLatch.Enqueue(LoadGate), currentFile);
loadedFileList.Add(data);
loadStates.Add(data.Done);
end;
@@ -496,7 +495,7 @@ begin
liveData := TFuture<TArray<TDataPoint>>.Null;
if liveFilePath <> '' then
begin
liveData := LoadDataFile(LoadGate, liveFilePath);
liveData := LoadDataFile(TLatch.Enqueue(LoadGate), liveFilePath);
loadedFileList.Add(liveData);
loadStates.Add(liveData.Done);
end;
@@ -520,7 +519,7 @@ begin
var tickList := TList<TDataPoint>.Create;
try
var totalTicks := Length(liveData.Value);
var overallLastTabTickTime := 0.0;
var overallLastTabTickTime: TDateTime := 0;
for var P in loadedFiles do
Inc(totalTicks, Length(P.Value));
@@ -529,15 +528,12 @@ begin
for var P in loadedFiles do
begin
if Length(P.Value) > 0 then
begin
for var iterTickData in P.Value do
if iterTickData.OADateTime > overallLastTabTickTime then
begin
tickList.Add(iterTickData);
overallLastTabTickTime := iterTickData.OADateTime;
end;
end;
for var iterTickData in P.Value do
if overallLastTabTickTime < iterTickData.OADateTime then
begin
tickList.Add(iterTickData);
overallLastTabTickTime := iterTickData.OADateTime;
end;
end;
Result := tickList.ToArray;
finally
+149 -3
View File
@@ -7,7 +7,9 @@ uses
System.Generics.Collections,
Myc.Lazy,
Myc.Trade.DataPoint,
Myc.Trade.DataSeries;
Myc.Trade.DataSeries,
Myc.Signals, // Added for TLatch
Myc.Futures; // Added for TFuture
type
IDataProvider = interface
@@ -15,7 +17,7 @@ type
procedure Fetch;
end;
IDataServer<T> = interface
IDataServer<T> = interface(IDataProvider)
['{A6E246A2-E84E-49AB-A63E-333E561E488C}']
function GetData: TMutable<TArray<T>>;
function GetIsLiveData: TMutable<Boolean>;
@@ -41,10 +43,154 @@ type
function CreateDataServer: IDataServer<T>; virtual; abstract;
end;
TFileStreamServerNode<T> = class(TDataServerNode<T>)
TTABFileServer = class(TDataServer<ITickData>)
private
FFilename: String;
// The maximum number of data points to be produced per Fetch call.
FMaxFetch: Integer;
FHasNewData: TEvent;
FNeedNewChunk: Boolean;
FIsLiveData: TMutable<Boolean>.IWriteable;
// Internal state
FCurrentFileName: string;
FCurrentData: TFuture<TArray<TAskBid.TTick>>;
FNextFileName: string;
FNextData: TFuture<TArray<TAskBid.TTick>>;
FData: TMutable<TArray<ITickData>>;
FCurrPosInFile: Int64;
FCurrChunk: TArray<ITickData>;
FLoadGate: TLatch;
FCurrentIdx: Int64;
FLastTimeStamp: TDateTime;
function ConvertTicks(var Idx: Int64; const Ticks: TArray<TAskBid.TTick>): TArray<ITickData>;
function UpdateChunk: TArray<ITickData>;
protected
procedure Fetch; override;
function GetData: TMutable<TArray<ITickData>>; override;
function GetIsLiveData: TMutable<Boolean>; override;
public
constructor Create(const AFilename: String; AMaxFetch: Integer);
end;
implementation
uses
System.IOUtils;
{ TTABFileServer<T> }
constructor TTABFileServer.Create(const AFilename: String; AMaxFetch: Integer);
begin
inherited Create;
FFilename := AFilename;
FMaxFetch := AMaxFetch;
FNextData := TFuture<TArray<TAskBid.TTick>>.Null;
FNeedNewChunk := true;
FIsLiveData := TMutable<Boolean>.CreateWriteable(false);
FHasNewData := TEvent.CreateEvent;
FData := TMutable<TArray<ITickData>>.Construct(FHasNewData.Signal, function: TArray<ITickData> begin Result := UpdateChunk; end);
end;
function TTABFileServer.ConvertTicks(var Idx: Int64; const Ticks: TArray<TAskBid.TTick>): TArray<ITickData>;
begin
SetLength(Result, Length(Ticks));
for var i := 0 to High(Ticks) do
begin
Result[i] := TDataPoint<ITick>.Create(Idx, Ticks[i].OADateTime, 1, TTick.Create(Ticks[i].Data.Ask, Ticks[i].Data.Bid));
inc(Idx);
end;
end;
procedure TTABFileServer.Fetch;
begin
// Check if the source filename has changed.
if (FFilename <> FCurrentFileName) and (FFilename <> '') then
begin
// Filename has changed, initialize by loading the new file.
FCurrentFileName := FFilename;
FCurrentData := TAskBid.LoadDataFile(TLatch.Enqueue(FLoadGate), FCurrentFileName);
FCurrPosInFile := 0;
FCurrentIdx := 0;
FIsLiveData.SetValue(false);
FLastTimeStamp := 0;
FFilename := '';
FNextFileName := FindNextDataFile(FCurrentFileName);
if FNextFileName <> '' then
FNextData := TAskBid.LoadDataFile(TLatch.Enqueue(FLoadGate), FNextFileName);
end;
FHasNewData.Notify;
FNeedNewChunk := true;
FCurrChunk := nil;
end;
function TTABFileServer.GetData: TMutable<TArray<ITickData>>;
begin
Result := FData;
end;
function TTABFileServer.GetIsLiveData: TMutable<Boolean>;
begin
Result := FIsLiveData;
end;
function TTABFileServer.UpdateChunk: TArray<ITickData>;
begin
if not FNeedNewChunk then
exit(FCurrChunk);
FNeedNewChunk := false;
if FCurrentData.Done.IsSet then
begin
SetLength(FCurrChunk, FMaxFetch);
var n := 0;
while n < FMaxFetch do
begin
if FCurrPosInFile >= Length(FCurrentData.Value) then
begin
// Next File!
FCurrentData := FNextData;
FCurrentFileName := FNextFileName;
FCurrPosInFile := 0;
FNextFileName := '';
FNextData := TFuture<TArray<TAskBid.TTick>>.Null;
if FCurrentFileName <> '' then
begin
FNextFileName := FindNextDataFile(FCurrentFileName);
if FNextFileName <> '' then
FNextData := TAskBid.LoadDataFile(TLatch.Enqueue(FLoadGate), FNextFileName);
end
else
begin
// We're done with this series
FIsLiveData.SetValue(true);
end;
SetLength(FCurrChunk, n);
break;
end;
var currData := FCurrentData.Value[FCurrPosInFile];
if FLastTimeStamp < currData.OADateTime then
begin
FLastTimeStamp := currData.OADateTime;
FCurrChunk[n] :=
TDataPoint<ITick>.Create(FCurrentIdx, FLastTimeStamp, 1, TTick.Create(currData.Data.Ask, currData.Data.Bid));
inc(FCurrentIdx);
inc(n);
end;
inc(FCurrPosInFile);
end;
end;
Result := FCurrChunk;
end;
end.
+2 -1
View File
@@ -35,7 +35,8 @@ uses
Myc.Test.Signals.Dirty in '..\Src\Myc.Test.Signals.Dirty.pas',
Myc.Trade.DataPoint in '..\Src\Myc.Trade.DataPoint.pas',
Myc.Trade.DataServer in '..\Src\Myc.Trade.DataServer.pas',
Myc.Trade.Node in '..\Src\Myc.Trade.Node.pas';
Myc.Trade.Node in '..\Src\Myc.Trade.Node.pas',
Myc.Test.Trade.DataServer in '..\Src\Myc.Test.Trade.DataServer.pas';
{ keep comment here to protect the following conditional from being removed by the IDE when adding a unit }
{$IFNDEF TESTINSIGHT}
+12 -3
View File
@@ -4,7 +4,7 @@
<ProjectVersion>20.3</ProjectVersion>
<FrameworkType>None</FrameworkType>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config>
<Config Condition="'$(Config)'==''">Release</Config>
<Platform Condition="'$(Platform)'==''">Win64</Platform>
<ProjectName Condition="'$(ProjectName)'==''">MycTests</ProjectName>
<TargetedPlatforms>3</TargetedPlatforms>
@@ -58,7 +58,7 @@
<UsingDelphiRTL>true</UsingDelphiRTL>
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
<Icns_MainIcns>$(BDS)\bin\delphi_PROJECTICNS.icns</Icns_MainIcns>
<DCC_UnitSearchPath>$(DUnitX);..\Src;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
<DCC_UnitSearchPath>$(DUnitX);T:\Myc\Src;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
<SanitizedProjectName>MycTests</SanitizedProjectName>
<VerInfo_Locale>1031</VerInfo_Locale>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
@@ -93,6 +93,9 @@ $(PreBuildEvent)]]></PreBuildEvent>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
<DCC_RemoteDebug>false</DCC_RemoteDebug>
<VerInfo_Locale>1033</VerInfo_Locale>
<Manifest_File>(None)</Manifest_File>
<AppDPIAwarenessMode>none</AppDPIAwarenessMode>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win64)'!=''">
<VerInfo_Locale>1033</VerInfo_Locale>
@@ -133,6 +136,7 @@ $(PreBuildEvent)]]></PreBuildEvent>
<DCCReference Include="..\Src\Myc.Trade.DataPoint.pas"/>
<DCCReference Include="..\Src\Myc.Trade.DataServer.pas"/>
<DCCReference Include="..\Src\Myc.Trade.Node.pas"/>
<DCCReference Include="..\Src\Myc.Test.Trade.DataServer.pas"/>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
@@ -153,7 +157,12 @@ $(PreBuildEvent)]]></PreBuildEvent>
<Source>
<Source Name="MainSource">MycTests.dpr</Source>
</Source>
<Excluded_Packages/>
<Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\bcboffice2k290.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\bcbofficexp290.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k290.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp290.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
</Excluded_Packages>
</Delphi.Personality>
<Deployment Version="5">
<DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule">