Files
MycLib/Src/Myc.Aura.Module.pas
T
2025-07-14 15:07:36 +02:00

815 lines
31 KiB
ObjectPascal

(*
---
## Aura Module API Documentation
This unit defines the core interfaces and records for the Aura system, designed for robust algorithmic trading strategy development,
backtesting, and optimization. It encapsulates key concepts for defining strategies, executing backtests, performing walk-forward
optimizations, and conducting statistical robustness analysis via Monte Carlo simulations.
---
### Core Interfaces and Records
#### `IAuraObject`
Base interface for all Aura objects, providing a common `Name` property for identification.
* `Name`: A writeable string representing the object's name.
#### `TAuraArray<T: IAuraObject>`
A record providing a mutable, observable array-like collection for `IAuraObject` instances. It wraps a `TWriteable<TArray<T>>` and offers basic array manipulation methods.
* `Items`: A writeable array of `IAuraObject` instances.
* `Insert(Idx: Integer; const Item: T)`: Inserts an item at a specified index.
* `Delete(Idx: Integer)`: Deletes an item at a specified index.
* `IndexOf(const Item: T)`: Returns the index of a given item.
#### `IAuraLiveObject`
Extends `IAuraObject` for entities that are dynamically produced and actively executing operations, providing logging capabilities and a running status.
* `Log`: A `TStrings` object for logging events and status messages.
* `IsRunning`: Indicates whether the object is currently active.
#### `IAuraNode`
Extends `IAuraObject` for objects that can be part of a hierarchical structure and can be serialized.
* `Caption`: A human-readable representation of the object's name.
* `Serialize(const Write: TJsonWriter)`: Serializes the object's state to a JSON writer.
#### `IAuraChilds<T: IAuraNode>`
A generic interface for `IAuraNode`s that can have child nodes, enabling hierarchical organization within the Aura system.
* `Items`: A `TAuraArray` containing the child nodes.
#### `TAuraParameterDef`
Defines the metadata for a single strategy parameter, including its name, type, and default value.
* `Name`: The name of the parameter.
* `ParamType`: The data type of the parameter (e.g., integer, float, string, UTC time).
* `DefaultValue`: The default value for the parameter, stored as a `TAuraParameterValue`.
#### `TAuraParameterRecordDef`
Represents a collection of `TAuraParameterDef` records, defining all parameters for a specific strategy. This is an alias for `TArray<TAuraParameterDef>`.
#### `IAuraBot`
An interface representing an instance that executes a trading strategy with given parameters over a specified time period.
* `PnL`: A mutable data series representing the Profit and Loss (PnL) curve of the bot's execution.
#### `IAuraStrategy`
Defines a trading strategy, providing methods to create `IAuraBot` instances and specifying its parameter structure.
* `CreateBot(const Parameters: TArray<TAuraParameterValue>; StartTime, EndTime: TDateTime)`: Creates and returns an `IAuraBot` instance configured with the given parameters and time range.
* `ParameterRecordDef`: Defines the set of parameters expected by this strategy.
#### `TAuraTradePerformance`
A record encapsulating key performance metrics from a backtest or optimization run.
* `PnL`: Total Profit and Loss.
* `SharpeRatio`: Risk-adjusted return.
* `MaxDrawdown`: Maximum peak-to-trough decline.
* `ProfitFactor`: Ratio of gross profits to gross losses.
* `CalmarRatio`: Annualized return divided by the maximum drawdown.
* `WinRate`: Percentage of winning trades.
#### `TAuraMonteCarloResult`
Stores the results of a Monte Carlo simulation, providing a probabilistic distribution of `TAuraTradePerformance` outcomes.
* `Percentile`: An array of `TAuraTradePerformance` records, sorted by PnL and distributed into 10% percentiles, allowing for statistical risk assessment.
#### `IAuraTradeResult`
Represents the comprehensive outcome of a trade simulation (e.g., from a backtest or optimization), including performance metrics, trade details, and the ability to perform Monte Carlo analysis.
* `Performance`: The `TAuraTradePerformance` metrics for this result.
* `Trades`: A `TDataSeries<Double>` representing the PnLs of individual trades, serving as the basis for Monte Carlo simulation.
* `CalcMonteCarloSimulation(Steps: Integer)`: Asynchronously performs a Monte Carlo simulation on the `Trades` data, returning a `TFuture` that resolves to a `TAuraMonteCarloResult`.
#### `TAuraTimeRange`
A record defining a specific time window with a start and end date/time.
* `StartTime`: The start of the time range.
* `EndTime`: The end of the time range.
#### `IAuraBacktest`
An interface for executing a single backtest of a trading strategy.
* `BacktestResult`: A `TFuture` that resolves to the `IAuraTradeResult` of this backtest.
* `Bot`: The `IAuraBot` instance executing the backtest.
* `Parameters`: The specific parameters used for this backtest.
* `Strategy`: The `IAuraStrategy` being backtested.
* `TimeRange`: The historical time window over which the backtest is conducted.
#### `IAuraParameterOptimization`
Represents a single optimization slot (window) within a Walk-Forward Optimization process. It manages the execution of multiple in-sample backtests to find optimal parameters, followed by an out-of-sample test.
* `InSampleTests`: A mutable array of `IAuraBacktest` instances representing the backtests run during the in-sample optimization phase. New tests are added, and less optimal ones may be removed.
* `OutOfSampleTest`: A mutable `IAuraBacktest` representing the test run with the best-fit parameters from the in-sample optimization on the subsequent out-of-sample data.
#### `IAuraWalkForwardOptimizer`
Orchestrates the entire Walk-Forward Optimization (WFO) process, coordinating multiple `IAuraParameterOptimization` slots sequentially to test strategy adaptability across various market phases.
* `OptimizationResult`: A `TFuture` that resolves to the aggregated `IAuraTradeResult` representing the combined performance of all out-of-sample tests.
* `Slot`: An array of `IAuraParameterOptimization` instances, each representing a distinct optimization window.
#### `IAuraParameterNode`
Represents a single configurable parameter for optimization algorithms, allowing its value to be set and observed.
* `Value`: A mutable `TAuraParameterValue` representing the parameter's current setting.
#### `IAuraParameterList`
An alias for `IAuraChilds<IAuraParameterNode>`, providing a structured way to manage collections of `IAuraParameterNode`s.
#### `IAuraStudy`
Base interface for all types of strategy analysis studies (e.g., single backtests, parameter optimizations, WFOs).
* `EventLog`: A `TStrings` object for logging events specific to the study.
* `Strategy`: The `IAuraStrategy` that is the subject of the study.
#### `TAuraParameterRange`
Defines the allowed range for a strategy parameter during optimization.
* `MinValue`: The minimum allowed value for the parameter, as a `TAuraParameterValue`.
* `MaxValue`: The maximum allowed value for the parameter, as a `TAuraParameterValue`.
#### `IAuraBacktestStudy`
A specialized `IAuraStudy` for setting up and initiating a single backtest.
* `TimeRange`: The `TAuraTimeRange` for the backtest.
* `Start`: Initiates and returns an `IAuraBacktest` instance.
#### `IAuraParameterOptimizationStudy`
A specialized `IAuraStudy` for configuring and initiating a parameter optimization process (e.g., using genetic algorithms) over a specific time range.
* `Parameters`: An `IAuraChilds` collection of `IAuraParameterNode`s defining the configuration parameters for the optimization algorithm itself (e.g., max generations, population size).
* `TimeRange`: The `TAuraTimeRange` for the optimization.
* `Start`: Initiates and returns an `IAuraParameterOptimization` instance.
#### `IAuraWFOStudy`
A specialized `IAuraStudy` for configuring and initiating a Walk-Forward Optimization process.
* `ParameterRange[Idx: Integer]`: A writeable `TAuraParameterRange` defining the search space for each strategy parameter during the optimization phases.
* `NumSlots`: A writeable integer indicating the number of time windows (slots) for the WFO.
* `Start`: Initiates and returns an `IAuraWalkForwardOptimizer` instance.
#### `IAuraTradingMode`
An enumeration defining different operational modes for a trading environment.
* `tmTesting`: Mode for historical backtesting.
* `tmSim`: Mode for simulated live trading (paper trading).
* `tmLive`: Mode for actual live trading.
#### `IAuraWorkspace`
Represents the scope of a complete testing and trading environment, containing various studies and managing the overall trading mode.
* `WalkForwardAnalysis`: An `IAuraChilds` collection of `IAuraWFOStudy` instances.
* `Backtests`: An `IAuraChilds` collection of `IAuraBacktestStudy` instances.
* `ParameterOptimizations`: An `IAuraChilds` collection of `IAuraParameterOptimizationStudy` instances.
* `TradingMode`: A writeable `IAuraTradingMode` indicating the current operational mode.
#### `IAuraModule`
An interface for creating instances of `IAuraStrategy`. Used for managing available strategy types.
* `CreateStrategy`: Creates and returns a new `IAuraStrategy` instance.
#### `IAuraApplication`
The application-level singleton, serving as the root for serialization and providing access to all defined strategies and workspaces.
* `Strategies`: An `IAuraChilds` collection of `IAuraModule` instances.
* `Workspaces`: An `IAuraChilds` collection of `IAuraWorkspace` instances.
---
*)
unit Myc.Aura.Module;
interface
uses
System.JSON.Writers,
System.Classes,
System.Generics.Collections,
Myc.Signals,
Myc.Futures,
Myc.Mutable,
Myc.Trade.DataPoint,
Myc.Aura.Parameter;
type
// Base class of all Aura objects
IAuraObject = interface
function GetName: TWriteable<String>;
property Name: TWriteable<String> read GetName;
end;
TAuraArray<T: IAuraObject> = record
private
FArray: TWriteable<TArray<T>>;
function GetItems: TWriteable<TArray<T>>;
public
class operator Initialize(out Dest: TAuraArray<T>);
procedure Insert(Idx: Integer; const Item: T);
procedure Delete(Idx: Integer);
function IndexOf(const Item: T): Integer;
property Items: TWriteable<TArray<T>> read GetItems;
end;
// Base class for objects that are dynamically produced and are executing
IAuraLiveObject = interface(IAuraObject)
function GetLog: TStrings;
function IsRunning: Boolean;
property Log: TStrings read GetLog;
end;
IAuraNode = interface(IAuraObject)
function GetCaption: string;
// Serialize the whole project
procedure Serialize(const Write: TJsonWriter);
// Pretty print of Name
property Caption: string read GetCaption;
end;
IAuraChilds<T> = interface(IAuraNode)
function GetItems: TWriteable<TArray<T>>;
procedure Insert(Idx: Integer; const Item: T);
procedure Delete(Idx: Integer);
function IndexOf(const Item: T): Integer;
// Nodes to add as childs in hierarchical representation
property Items: TWriteable<TArray<T>> read GetItems;
end;
TAuraChilds<T> = record
private
FChilds: IAuraChilds<T>;
function GetCaption: string;
public
constructor Create(const AChilds: IAuraChilds<T>);
class operator Implicit(const A: IAuraChilds<T>): TAuraChilds<T>; overload;
class operator Implicit(const A: TAuraChilds<T>): IAuraChilds<T>; overload;
procedure Serialize(const Write: TJsonWriter);
procedure Insert(Idx: Integer; const Item: T);
procedure Delete(Idx: Integer);
function IndexOf(const Item: T): Integer;
property Caption: string read GetCaption;
end;
TAuraParameterDef = record
Name: String;
ParamType: TAuraParameterType;
DefaultValue: TAuraParameterValue;
end;
TAuraParameterRecordDef = TArray<TAuraParameterDef>;
// A bot executes a strategy
IAuraBot = interface(IAuraLiveObject)
function GetPnL: TMutable<TDataSeries<Double>>;
// Zero-based PnL series
property PnL: TMutable<TDataSeries<Double>> read GetPnL;
end;
// A strategy creates a bot that executes that strategy with given parameters and within a given time slot.
IAuraStrategy = interface(IAuraObject)
function CreateBot(const Parameters: TArray<TAuraParameterValue>; StartTime, EndTime: TDateTime): IAuraBot;
function GetParameterRecordDef: TAuraParameterRecordDef;
// Defines the parameters of this strategy
property ParameterRecordDef: TAuraParameterRecordDef read GetParameterRecordDef;
end;
// The performance of a backtest or walk forward optimization
TAuraTradePerformance = record
PnL: Double;
SharpeRatio, MaxDrawdown, ProfitFactor, CalmarRatio, WinRate: Double;
end;
TAuraMonteCarloResult = record
// Performance sorted by PnL and distributed to percentiles of 10% each
Percentile: array[0..10] of TAuraTradePerformance;
end;
IAuraTradeResult = interface
function GetPerformance: TAuraTradePerformance;
function GetTrades: TDataSeries<Double>;
// Perform Monte Carlo Simulation and generate performance distribution
function CalcMonteCarloSimulation(Steps: Integer): TFuture<TAuraMonteCarloResult>;
// PnLs of each trade = Equity curve
property Trades: TDataSeries<Double> read GetTrades;
// The performance of this equity curve
property Performance: TAuraTradePerformance read GetPerformance;
end;
TAuraTimeRange = record
StartTime: TDateTime;
EndTime: TDateTime;
end;
// Backtesting
IAuraBacktest = interface(IAuraLiveObject)
function GetParameters: TArray<TAuraParameterValue>;
function GetStrategy: IAuraStrategy;
function GetBot: IAuraBot;
function GetBacktestResult: TFuture<IAuraTradeResult>;
function GetTimeRange: TAuraTimeRange;
// The bot executing the backtest (generated by Strategy.CreateBot with the given parameters).
property Bot: IAuraBot read GetBot;
// The backtest result
property BacktestResult: TFuture<IAuraTradeResult> read GetBacktestResult;
// The strategy parameters for this backtest
property Parameters: TArray<TAuraParameterValue> read GetParameters;
// The strategy to backtest
property Strategy: IAuraStrategy read GetStrategy;
// The tested time window
property TimeRange: TAuraTimeRange read GetTimeRange;
end;
// Generates parameter sets using genetic algorithms (or other techniques).
// Executes backtests and finds the best run by evaluating the backtest results.
IAuraParameterOptimization = interface(IAuraLiveObject)
function GetInSampleTests: TMutable<TArray<IAuraBacktest>>;
function GetOutOfSampleTest: TMutable<IAuraBacktest>;
// The running in-sample-tests. New tests will be added until the optimization stops.
property InSampleTests: TMutable<TArray<IAuraBacktest>> read GetInSampleTests;
// After in sample testing is finished, the out-of-sample-test with the best parameter set is executed.
property OutOfSampleTest: TMutable<IAuraBacktest> read GetOutOfSampleTest;
end;
// Walk-Forward-Optimizer
IAuraWalkForwardOptimizer = interface(IAuraLiveObject)
function GetOptimizationResult: TFuture<IAuraTradeResult>;
function GetSlot: TArray<IAuraParameterOptimization>;
// When optimization is ready, this will contain the result for the combined WFO slots
property OptimizationResult: TFuture<IAuraTradeResult> read GetOptimizationResult;
// The concurrently running optimization slots
property Slot: TArray<IAuraParameterOptimization> read GetSlot;
end;
// A Parameter Value
IAuraParameterNode = interface(IAuraNode)
function GetValue: TMutable<TAuraParameterValue>;
property Value: TMutable<TAuraParameterValue> read GetValue;
end;
IAuraParameterList = IAuraChilds<IAuraParameterNode>;
// A study on a strategy
IAuraStudy = interface(IAuraNode)
function GetEventLog: TStrings;
function GetStrategy: IAuraStrategy;
property EventLog: TStrings read GetEventLog;
// The Strategy to optimize
property Strategy: IAuraStrategy read GetStrategy;
end;
TAuraParameterRange = record
MinValue, MaxValue: TAuraParameterValue;
end;
// Study on a single backtest
IAuraBacktestStudy = interface(IAuraStudy)
function GetTimeRange: TAuraTimeRange;
function Start: IAuraBacktest;
property TimeRange: TAuraTimeRange read GetTimeRange;
end;
// Study parameter optimization
IAuraParameterOptimizationStudy = interface(IAuraStudy)
function GetParameters: IAuraChilds<IAuraParameterNode>;
function GetTimeRange: TAuraTimeRange;
function Start: IAuraParameterOptimization;
// Depending on the implementation this may be MaxGenerations, PopulationSize, Mutations, etc
property Parameters: IAuraChilds<IAuraParameterNode> read GetParameters;
property TimeRange: TAuraTimeRange read GetTimeRange;
end;
// Walk forward optimization
IAuraWFOStudy = interface(IAuraStudy)
function GetParameterRange(Idx: Integer): TWriteable<TAuraParameterRange>;
function GetNumSlots: TWriteable<Integer>;
// Starts WalkForwardOptimizer with the given number of NumSlots.
function Start: IAuraWalkForwardOptimizer;
// A list of parameter values to test, one for each parameter in the Strategy's parameter definition.
// This defines the parameter space for optimization algorithms.
property ParameterRange[Idx: Integer]: TWriteable<TAuraParameterRange> read GetParameterRange;
// Number of time slots (windows) to test.
property NumSlots: TWriteable<Integer> read GetNumSlots;
end;
TAuraTradingMode = (tmTesting, tmSim, tmLive);
// Repesents the scope of a workspace
IAuraWorkspace = interface(IAuraNode)
['{8485F7E7-F097-4CB8-8186-A6C9AE0048AF}']
// function GetWalkForwardAnalysis: IAuraChilds<IAuraWFOStudy>;
// function GetBacktests: IAuraChilds<IAuraBacktestStudy>;
// function GetParameterOptimizations: IAuraChilds<IAuraParameterOptimizationStudy>;
// function GetWalkForwardAnalysis: IAuraChilds<IAuraWFOStudy>;
// function GetBacktests: IAuraChilds<IAuraBacktestStudy>;
// function GetParameterOptimizations: IAuraChilds<IAuraParameterOptimizationStudy>;
// property WalkForwardAnalysis: IAuraChilds<IAuraWFOStudy> read GetWalkForwardAnalysis;
// property Backtests: IAuraChilds<IAuraBacktestStudy> read GetBacktests;
// property ParameterOptimizations: IAuraChilds<IAuraParameterOptimizationStudy> read GetParameterOptimizations;
// property WalkForwardAnalysis: IAuraChilds<IAuraWFOStudy> read GetWalkForwardAnalysis;
// property Backtests: IAuraChilds<IAuraBacktestStudy> read GetBacktests;
// property ParameterOptimizations: IAuraChilds<IAuraParameterOptimizationStudy> read GetParameterOptimizations;
function GetTradingMode: TWriteable<TAuraTradingMode>;
function GetStudies: TAuraArray<IAuraStudy>;
property TradingMode: TWriteable<TAuraTradingMode> read GetTradingMode;
property Studies: TAuraArray<IAuraStudy> read GetStudies;
end;
IAuraModule = interface
procedure SetupWorkspace(const Workspace: IAuraWorkspace);
end;
// Application singleton, the root for serialization
IAuraApplication = interface(IAuraNode)
function GetModuleNames: TMutable<TArray<String>>;
function GetModules(const Name: String): IAuraModule;
function GetWorkspaces: IAuraChilds<IAuraWorkspace>;
procedure RegisterModule(const Name: String; const Module: IAuraModule);
property ModuleNames: TMutable<TArray<String>> read GetModuleNames;
property Modules[const Name: String]: IAuraModule read GetModules;
property Workspaces: IAuraChilds<IAuraWorkspace> read GetWorkspaces;
end;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Generic implementation for a collection of child nodes.
TMycAuraObject = class(TInterfacedObject, IAuraObject)
private
FName: TWriteable<String>;
function GetName: TWriteable<String>;
procedure Serialize(const Write: TJsonWriter); virtual;
public
constructor Create(const AName: string);
end;
// Generic implementation for a collection of child nodes.
TMycAuraNode = class(TMycAuraObject, IAuraNode)
private
protected
function GetCaption: string; virtual;
procedure Serialize(const Write: TJsonWriter); override;
end;
// Generic implementation for a collection of child nodes.
TMycAuraChilds<T: IAuraNode> = class(TInterfacedObject, IAuraChilds<T>)
private
FName: TWriteable<String>;
FItems: TWriteable<TArray<T>>;
function GetCaption: string;
function GetItems: TWriteable<TArray<T>>;
function GetName: TWriteable<String>;
procedure Serialize(const Write: TJsonWriter);
public
constructor Create(const AName: string);
procedure Delete(Idx: Integer);
function IndexOf(const Item: T): Integer;
procedure Insert(Idx: Integer; const Item: T);
end;
TMycAuraWorkspace = class(TMycAuraNode, IAuraWorkspace)
private
FTradingMode: TWriteable<TAuraTradingMode>;
FStudies: TAuraArray<IAuraStudy>;
function GetStudies: TAuraArray<IAuraStudy>;
function GetTradingMode: TWriteable<TAuraTradingMode>;
protected
function GetCaption: string; override;
public
constructor Create(const AName: string; TradingMode: TAuraTradingMode);
end;
TMycAuraApplication = class(TInterfacedObject, IAuraApplication)
private
FName: TWriteable<String>;
FModules: TDictionary<String, IAuraModule>;
FModulesChanged: TEvent;
FModuleNames: TMutable<TArray<String>>;
FWorkspaces: TAuraChilds<IAuraWorkspace>;
function GetCaption: string;
function GetName: TWriteable<String>;
function GetModuleNames: TMutable<TArray<String>>;
function GetModules(const Name: String): IAuraModule;
function GetWorkspaces: IAuraChilds<IAuraWorkspace>;
procedure Serialize(const Write: TJsonWriter);
public
constructor Create;
procedure RegisterModule(const Name: String; const Module: IAuraModule);
end;
implementation
{ TMycAuraObject }
constructor TMycAuraObject.Create(const AName: string);
begin
inherited Create;
FName := TWriteable<String>.CreateWriteable;
FName.Value := AName;
end;
function TMycAuraObject.GetName: TWriteable<String>;
begin
Result := FName;
end;
procedure TMycAuraObject.Serialize(const Write: TJsonWriter);
begin
Write.WriteStartObject;
Write.WritePropertyName('Name');
Write.WriteValue(FName.Value);
Write.WriteEndObject;
end;
{ TMycAuraNode }
function TMycAuraNode.GetCaption: string;
begin
Result := FName.Value;
end;
procedure TMycAuraNode.Serialize(const Write: TJsonWriter);
begin
Write.WriteStartObject;
inherited;
Write.WriteEndObject;
end;
{ TAuraArray<T> }
class operator TAuraArray<T>.Initialize(out Dest: TAuraArray<T>);
begin
Dest.FArray := TWriteable<TArray<T>>.CreateWriteable;
end;
procedure TAuraArray<T>.Delete(Idx: Integer);
var
oldArray: TArray<T>;
newArray: TArray<T>;
oldCount: Integer;
begin
oldArray := FArray.Value;
oldCount := Length(oldArray);
if (Idx < 0) or (Idx >= oldCount) then
exit;
SetLength(newArray, oldCount - 1);
// Copy elements before the index
if Idx > 0 then
TArray.Copy<T>(oldArray, newArray, 0, 0, Idx);
// Copy elements after the index
if Idx < oldCount - 1 then
TArray.Copy<T>(oldArray, newArray, Idx + 1, Idx, oldCount - Idx - 1);
FArray.Value := newArray;
end;
procedure TAuraArray<T>.Insert(Idx: Integer; const Item: T);
var
oldArray: TArray<T>;
newArray: TArray<T>;
oldCount: Integer;
begin
oldArray := FArray.Value;
if not Assigned(oldArray) then
SetLength(oldArray, 0);
oldCount := Length(oldArray);
if Idx < 0 then
Idx := 0;
if Idx > oldCount then
Idx := oldCount;
SetLength(newArray, oldCount + 1);
// Copy elements before the index
if Idx > 0 then
TArray.Copy<T>(oldArray, newArray, 0, 0, Idx);
newArray[Idx] := Item;
// Copy elements after the index
if Idx < oldCount then
TArray.Copy<T>(oldArray, newArray, Idx, Idx + 1, oldCount - Idx);
FArray.Value := newArray;
end;
function TAuraArray<T>.GetItems: TWriteable<TArray<T>>;
begin
Result := FArray;
end;
function TAuraArray<T>.IndexOf(const Item: T): Integer;
begin
Result := TArray.IndexOf<T>(FArray.Value, Item);
end;
{ TMycAuraChilds<T> }
constructor TMycAuraChilds<T>.Create(const AName: string);
begin
inherited Create;
FName := TWriteable<String>.CreateWriteable(AName);
FItems := TWriteable<TArray<T>>.CreateWriteable;
end;
procedure TMycAuraChilds<T>.Delete(Idx: Integer);
var
oldArray: TArray<T>;
newArray: TArray<T>;
oldCount: Integer;
begin
oldArray := FItems.Value;
oldCount := Length(oldArray);
if (Idx < 0) or (Idx >= oldCount) then
exit;
SetLength(newArray, oldCount - 1);
// Copy elements before the index
if Idx > 0 then
TArray.Copy<T>(oldArray, newArray, 0, 0, Idx);
// Copy elements after the index
if Idx < oldCount - 1 then
TArray.Copy<T>(oldArray, newArray, Idx + 1, Idx, oldCount - Idx - 1);
FItems.Value := newArray;
end;
function TMycAuraChilds<T>.GetCaption: string;
begin
Result := FName.Value;
end;
function TMycAuraChilds<T>.GetItems: TWriteable<TArray<T>>;
begin
Result := FItems;
end;
function TMycAuraChilds<T>.GetName: TWriteable<String>;
begin
Result := FName;
end;
function TMycAuraChilds<T>.IndexOf(const Item: T): Integer;
begin
Result := TArray.IndexOf<T>(FItems.Value, Item);
end;
procedure TMycAuraChilds<T>.Insert(Idx: Integer; const Item: T);
var
oldArray: TArray<T>;
newArray: TArray<T>;
oldCount: Integer;
begin
oldArray := FItems.Value;
if not Assigned(oldArray) then
SetLength(oldArray, 0);
oldCount := Length(oldArray);
if Idx < 0 then
Idx := 0;
if Idx > oldCount then
Idx := oldCount;
SetLength(newArray, oldCount + 1);
// Copy elements before the index
if Idx > 0 then
TArray.Copy<T>(oldArray, newArray, 0, 0, Idx);
newArray[Idx] := Item;
// Copy elements after the index
if Idx < oldCount then
TArray.Copy<T>(oldArray, newArray, Idx, Idx + 1, oldCount - Idx);
FItems.Value := newArray;
end;
procedure TMycAuraChilds<T>.Serialize(const Write: TJsonWriter);
var
Item: T;
arr: TArray<T>;
begin
Write.WriteStartObject;
inherited;
Write.WritePropertyName('Items');
Write.WriteStartArray;
arr := FItems.Value;
for Item in arr do
Item.Serialize(Write);
Write.WriteEndArray;
Write.WriteEndObject;
end;
{ TMycAuraApplication }
constructor TMycAuraApplication.Create;
begin
inherited Create;
FName := TWriteable<String>.CreateWriteable('Application');
FModules := TDictionary<String, IAuraModule>.Create;
FModulesChanged := TEvent.CreateEvent;
FModuleNames :=
TMutable<TArray<String>>.Construct(FModulesChanged.Signal, function: TArray<String> begin Result := FModules.Keys.ToArray; end);
FWorkspaces := TMycAuraChilds<IAuraWorkspace>.Create('Workspaces');
end;
function TMycAuraApplication.GetCaption: string;
begin
Result := FName.Value;
end;
function TMycAuraApplication.GetName: TWriteable<String>;
begin
Result := FName;
end;
function TMycAuraApplication.GetModuleNames: TMutable<TArray<String>>;
begin
Result := FModuleNames;
end;
function TMycAuraApplication.GetModules(const Name: String): IAuraModule;
begin
if not FModules.TryGetValue(Name, Result) then
Result := nil;
end;
function TMycAuraApplication.GetWorkspaces: IAuraChilds<IAuraWorkspace>;
begin
Result := FWorkspaces;
end;
procedure TMycAuraApplication.RegisterModule(const Name: String; const Module: IAuraModule);
begin
FModules.Add(Name, Module);
FModulesChanged.Notify;
end;
procedure TMycAuraApplication.Serialize(const Write: TJsonWriter);
begin
Write.WriteStartObject;
Write.WritePropertyName('Name');
Write.WriteValue(FName.Value);
Write.WritePropertyName('Workspaces');
FWorkspaces.Serialize(Write);
Write.WriteEndObject;
end;
function CreateAuraApplication: IAuraApplication;
begin
Result := TMycAuraApplication.Create;
end;
constructor TMycAuraWorkspace.Create(const AName: string; TradingMode: TAuraTradingMode);
begin
inherited Create(AName);
FTradingMode := TWriteable<TAuraTradingMode>.CreateWriteable(TradingMode);
end;
function TMycAuraWorkspace.GetCaption: string;
begin
var mode := '';
case FTradingMode.Value of
tmTesting: mode := ' (Test)';
tmSim: mode := ' (Sim)';
tmLive: mode := ' (Live)';
end;
Result := inherited GetCaption + mode;
end;
function TMycAuraWorkspace.GetStudies: TAuraArray<IAuraStudy>;
begin
Result := FStudies;
end;
function TMycAuraWorkspace.GetTradingMode: TWriteable<TAuraTradingMode>;
begin
Result := FTradingMode;
end;
constructor TAuraChilds<T>.Create(const AChilds: IAuraChilds<T>);
begin
FChilds := AChilds;
end;
procedure TAuraChilds<T>.Delete(Idx: Integer);
begin
FChilds.Delete(Idx);
end;
function TAuraChilds<T>.GetCaption: string;
begin
Result := FChilds.Caption;
end;
function TAuraChilds<T>.IndexOf(const Item: T): Integer;
begin
Result := FChilds.IndexOf(Item);
end;
procedure TAuraChilds<T>.Insert(Idx: Integer; const Item: T);
begin
FChilds.Insert(Idx, Item);
end;
procedure TAuraChilds<T>.Serialize(const Write: TJsonWriter);
begin
FChilds.Serialize(Write);
end;
class operator TAuraChilds<T>.Implicit(const A: IAuraChilds<T>): TAuraChilds<T>;
begin
Result.Create(A);
end;
class operator TAuraChilds<T>.Implicit(const A: TAuraChilds<T>): IAuraChilds<T>;
begin
Result := A.FChilds;
end;
end.