unit Myc.Trade.Broker; interface uses System.SysUtils, System.Classes, System.Generics.Collections, Myc.Data.Value, Myc.Ast.Types, Myc.Ast.Scope, Myc.Ast.RTL.TypeRegistry; {$TYPEINFO ON} type TSymProc = reference to procedure(const Symbol: String; Amount: Integer); // Das Interface, das im AST-Skript verfügbar sein wird. IMycBroker = interface ['{D8E9F1A2-B3C4-4D5E-F6A7-B8C9D0E1F2A3}'] function Buy(const Symbol: string; Amount: Integer; Price: Double): Boolean; function Sell(const Symbol: string; Amount: Integer; Price: Double): Boolean; function GetCash: Double; function GetPosition(const Symbol: string): Integer; // Iteriert über alle Positionen und ruft für jede den Callback auf. // Benötigt Registrierung von TProc. procedure ListPositions(const Callback: TSymProc); property Cash: Double read GetCash; end; procedure RegisterBroker(const Scope: IExecutionScope); implementation type TMockBroker = class(TInterfacedObject, IMycBroker) strict private FCash: Double; FPositions: TDictionary; public constructor Create(const AInitialCash: Double); destructor Destroy; override; function Buy(const Symbol: string; Amount: Integer; Price: Double): Boolean; function Sell(const Symbol: string; Amount: Integer; Price: Double): Boolean; function GetCash: Double; function GetPosition(const Symbol: string): Integer; procedure ListPositions(const Callback: TSymProc); end; // ----------------------------------------------------------------------------- // TMockBroker // ----------------------------------------------------------------------------- constructor TMockBroker.Create(const AInitialCash: Double); begin inherited Create; FCash := AInitialCash; FPositions := TDictionary.Create; end; destructor TMockBroker.Destroy; begin FPositions.Free; inherited Destroy; end; function TMockBroker.Buy(const Symbol: string; Amount: Integer; Price: Double): Boolean; var cost: Double; currentPos: Integer; begin cost := Amount * Price; if FCash < cost then exit(False); FCash := FCash - cost; if not FPositions.TryGetValue(Symbol, currentPos) then currentPos := 0; FPositions.AddOrSetValue(Symbol, currentPos + Amount); Result := True; end; function TMockBroker.Sell(const Symbol: string; Amount: Integer; Price: Double): Boolean; var revenue: Double; currentPos: Integer; begin revenue := Amount * Price; FCash := FCash + revenue; if not FPositions.TryGetValue(Symbol, currentPos) then currentPos := 0; FPositions.AddOrSetValue(Symbol, currentPos - Amount); Result := True; end; function TMockBroker.GetCash: Double; begin Result := FCash; end; function TMockBroker.GetPosition(const Symbol: string): Integer; begin if not FPositions.TryGetValue(Symbol, Result) then Result := 0; end; procedure TMockBroker.ListPositions(const Callback: TSymProc); var pair: TPair; begin // Safety check: Wenn das Script nil übergibt, nichts tun. if not Assigned(Callback) then exit; for pair in FPositions do begin Callback(pair.Key, pair.Value); end; end; // ----------------------------------------------------------------------------- // Registrierung // ----------------------------------------------------------------------------- procedure RegisterBroker(const Scope: IExecutionScope); begin // 1. Registrierung des Callback-Typs. // Dies ermöglicht dem TypeRegistry-Marshaller, die Signatur von Invoke(string, integer) zu analysieren // und AST-Lambdas (TDataValue.TFunc) in native TProc zu wrappen. TRtlTypeRegistry.RegisterType; // 2. Registrierung des Broker-Interfaces TRtlTypeRegistry.RegisterType; // 3. Factory registrieren var argTypes := TArray.Create(TTypes.Float); TRtlTypeRegistry.RegisterFactory( Scope, 'create-broker', argTypes, function(const Args: TArray): IMycBroker begin Result := TMockBroker.Create(Args[0].AsScalar.Value.AsDouble); end ); end; end.