# Handelsstrategie-Scripting-Studio

# Grundlagen Handelsstrategie-Scripting

Die Scripting-Engine erweitert die bisherigen Filter-Module, um eine freie programmierbare Script-Engine. Es soll hiermit ein sehr hohen Freiheitsgrad in der Umsetzung eigener Filter gegeben werden und Routineaufgaben in der Titel-und Kurspflege automatisiert werden können.

[![image-1655631326443.png](https://www.shareholder24.com/wiki/uploads/images/gallery/2022-06/scaled-1680-/image-1655631326443.png)](https://www.shareholder24.com/wiki/uploads/images/gallery/2022-06/image-1655631326443.png)

# Use-Cases

- <div class="details">Use-Case: Automatischer Export von Transaktionsdaten <span class="smalltext">(Shareholder R/2 Börsensoftware)</span></div>
- <div class="details">Use-Case: Automatische Watchliste auf Basis Indikator-Script <span class="smalltext">(Shareholder R/2 Börsensoftware</span></div>
- <div class="details">Use-Case: Automatische Stammdaten-Korrektur-Script <span class="smalltext">(Shareholder R/2 Börsensoftware)</span></div>

# Handelsstrategie-Studio

## Highlights

- Zugriff auf (alle) internen Datenobjekte
- Syntax-Highlighting
- Support einer produktiven und einer Entwicklungs-Version
- Support für Script-Bibliotheken, womit jedes Script von einem anderen aufgerufen werden kann. Dieser Mechanismus wird auch genutzt, um eine gemeinsame Bibliothek zu pflegen
- Hohe Ausführungsgeschwindigkeit (hier 0.4s über alle Aktien inkl. Log-Ausgaben)
- Source-Explorer

## Überblick

Die Scripting-Engine führte freie geschriebene Scripte aus. Die Skripte sind in einem Pascal-Syntax, wobei spätere Alternativ-Sprachen denkbar sind (VB, Java, JS, Python). Der Einsatz der Scripting-Engine soll durchgängig durch SHAREholder vollzogen werden, d.h. eine Verwendung sowohl in Filter-Systemen, Druck-Templates als auch indirekt in den Handelssystemen ist vorgesehen. Der Startpunkt (v13.5) liegt hier bei einem Filtersystemen. Dabei ist ein wesentliches Feature der Zugriff auf alle relevanten internen Datenobjekte von SHAREholder. Es stehen damit beispielsweise folgende Funktionen zur Verfügung, die nicht nur lesenden Charakter haben:

- Automatische Anlegen einer Watchliste auf der Basis von Stammdaten-Filtern
- Automatische Bereinigung von Kommentaren in den vorhandenen Transaktionen, um hier nachträglich Ergänzungen vorzunehmen
- Automatische Bereinigung von Kursdaten
- Automatisches manuelles Erzeugen von Dateien (z.B. CSV-Export-Dateien) mit eigenen komplexeren Ausdrücken
- Anzeige von interessanten Titeln nach eigenen Regeln in Filterlisten

Folgender Syntax wird grundsätzlich unterstützt, womit komplette Programmstrukturen unterstützt werden:

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="35c1253a-3b0f-4320-ba99-74effafeadc9" data-macro-name="code" id="bkmrk--3"><div class="codeContent panelContent pdl"><div class="syntaxhighlighter sh-eclipse  delphi">  
</div></div></div>```YAML
begin .. end
procedure & function
if .. then .. else
for .. to .. do .. step
while .. do
repeat .. until
try .. except & try .. finally blocks
case statements
array constructors (x:=[ 1, 2, 3 ];)
^ , * , / , and , + , - , or , <> , >=, <= , = , > , < , div , mod , xor , shl , shroperators
access to object properties and methods ( ObjectName.SubObject.Property)
```

Damit sind in Summe komplexere Scripte in SHAREholder nutzbar für verschiedene Strategie-Filter-Umsetzungen aber auch für eigene Massenoperationen bis hin zu Im-Exportszenarien. Die in SHAREholder genutzt objektorientierte Programmierung kann dabei in Skripten werden, um auf Daten und Methoden hierarchisch zuzugreifen. Auch das Schreiben eigener Klassen ist möglich (siehe eigenen Abschnitt).

## Editor

Der Editor setzt folgende Anforderungen um (Status v2.5):

- freie Codeeingabe
- Autovervollständigung
- Parameter-Darstellung d.h. innerhalb von Funktionen, Proceduren werden die erlaubten Parameter gezeigt
- Syntax-Highlighting auf die eingestellte Default-Sprache (hier Pascal/Delphi) und
- die Wiederverwendung von Code-Fragmenten durch Code-Bibliotheken
- Code-Folding d.h. das Ein/Ausklappen von Code-Fragmenten
- Snippet-Bibliothek, um sofort typische Fragmente nutzen zu können
- Automatischen Source-Explorer für aktuelle procedures und Variablen

# Dokumentation SHAREholder interne Methoden und Klassen

- Eine Dokumentation der aktuell zur Verfügung stehenden Methoden die in den Scripten genutzt und referenziert werden können, finden Sie unter:   
    [https://www.shareholder24.com/docs/classes.html](https://www.shareholder24.com/docs/classes.html)

# Syntax der Scripte

Scripte enthalten a) procedure und function declarations und b) Haupt-Blöcke.  
  
SCRIPT 1:

```PASCAL
procedure DoSomething;
begin
  CallSomething;
end;
 
begin
  DoSomething;
end;
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="2747afc9-2e66-4681-9be7-d69dd9536a6e" data-macro-name="code" id="bkmrk--6"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-eclipse  delphi" id="bkmrk--48"></div></div></div></div>SCRIPT 2:

```PASCAL
begin
  DoSomething;
end;

```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="dbf51d7d-4a7b-4129-96b8-849bca027fe5" data-macro-name="code" id="bkmrk--8"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-eclipse  delphi" id="bkmrk--49"></div></div></div></div>SCRIPT 3:

```PASCAL
function MyFunction;
begin
  result:='Ok!';
end;
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="8e1cb360-fc9d-4262-a505-6d57e6dc07df" data-macro-name="code" id="bkmrk--10"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-eclipse  delphi" id="bkmrk--50"></div></div></div></div>  
SCRIPT 4:

```PASCAL
CallSomethingElse;
```

<div class="syntaxhighlighter sh-confluence  delphi" id="bkmrk--11"></div>Statements sollten immer mit einem Semikolon ";" abgeschlossen werden.  
begin..end Blöcke können jederzeit genutzt werden, um Statements zu gruppieren. Diese sind damit mit der Code-Folding-Funktion später auch ein-ausklappbar.

## Identifier

Identifier Namen in Scripten (Variablen-Namen, function and procedure names, etc.) folgen folgenden einfachen Regeln:

- should begin with a character (a..z or A..Z), or '\_', and can be followed by alphanumeric chars or '\_' char.
- Cannot contain any other character os spaces.

Gültige Identifier:

```PASCAL
VarName
_Some
V1A2
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="fabda7fc-19a0-4316-b8e4-ecbbe87b4b00" data-macro-name="code" id="bkmrk--12"><div class="codeContent panelContent pdl"><div class="syntaxhighlighter sh-eclipse  delphi">  
</div></div></div>Einige ungültige Identifier:

```PASCAL
2Var
My Name
Some-more
This,is,not,valid
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="59f246b6-66c9-4a48-aa34-f5b8492aed99" data-macro-name="code" id="bkmrk--13"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-eclipse  delphi" id="bkmrk--51"></div></div></div></div>## Zuweisungen

Weisen Sie einen Wert oder ein Ausdrucksergebnis einer Variable oder Objekteigenschaft einfach mit ":=" zu.

```PASCAL
MyVar := 2;
Button.Caption := 'This ' + 'is ok.';
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="b8d63619-d548-4096-aade-f18da8be948f" data-macro-name="code" id="bkmrk--15"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-confluence  delphi" id="bkmrk--52"></div></div></div></div>## Zeichenketten

Zeichenketten/Strings (Folge von Zeichen) werden in einfachen Anführungszeichen (') deklariert. Charakter. Doppelte Anführungszeichen (") werden nicht verwendet. Sie können auch " verwenden, als Zeichen innerhalb einer Zeichenkette. Es ist nicht notwendig, den '+'-Operator zu verwenden, um Zeichen-Codes zu einer Zeichenkette hinzuzufügen z.B. New-Lines mit Code: #13 und Code: #10. Einige Beispiele:

```PASCAL
A := 'This is a text';
Str := 'Text '+'concat';
B := 'String with CR and LF char at the end'#13#10;
C := 'String with '#33#34' characters in the middle';
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="ef8bf44b-5512-463d-bb72-410848b03602" data-macro-name="code" id="bkmrk--17"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-confluence  delphi" id="bkmrk--53"></div></div></div></div>## Kommentare

Kommentare können innerhalb des Skripts eingefügt werden.  
Sie können

- //-Zeichen oder
- (\* \*) oder
- { } verwenden.  
      
    Bei Blöcke mit // Zeichen wird der Kommentar am Ende der Zeile beendet.

```PASCAL
//This is a comment before ShowMessage
ShowMessage('Ok');
 
(* This is another comment *)
ShowMessage('More ok!');
 
{ And this is a comment
with two lines }
ShowMessage('End of okays');
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="261bd5c4-28b0-47be-b7b7-548216238e6c" data-macro-name="code" id="bkmrk--19"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-confluence  delphi" id="bkmrk--54"></div></div></div></div>## Variablen

Es ist nicht notwendig, Variablentypen in einem Skript zu deklarieren, obwohl Sie jede beliebige Art darin verwenden können. Sie können eine Variable nur mit der var-Direktive und ihrem Namen deklarieren:

```PASCAL
procedure Msg;
var S;
begin
  S:='Hello world!';
  ShowMessage(S);
end;

var A;
begin
  A:=0;
  A:=A+1;
end;

var S: string;
begin
  S:='Hello World!';
  ShowMessage(S);
end;
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="33f68c99-20cf-4353-8de1-0da3219b59bc" data-macro-name="code" id="bkmrk--21"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-confluence  delphi" id="bkmrk--55"></div></div></div></div><div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="bae4bae6-ae29-4cba-913c-8b5bc8c911d0" data-macro-name="code" id="bkmrk--22"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-confluence  delphi" id="bkmrk--56"></div></div></div></div><div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="cf5e8618-aecc-40d6-af12-92cf56b8b3ee" data-macro-name="code" id="bkmrk--23"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-confluence  delphi" id="bkmrk--57"></div></div></div></div>### Arrays

Auch wenn der Typ der Variablen nicht erforderlich ist und in den meisten Fällen ignoriert wird, gibt es einige spezielle Typen, die eine eigene Bedeutung haben. Sie können so Variablen als Array deklarieren und die Variable wird automatisch  
als ein Variantenarray dieses Typs initialisiert:

```PASCAL
var Arr: array[0..10] of string;
begin
  Arr[1] := 'first';
end;
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="ce92eeed-3d7d-4942-8e4b-d56a73ba2300" data-macro-name="code" id="bkmrk--24"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-confluence  delphi" id="bkmrk--58"></div></div></div></div>Der Typ der Array-Elemente und der niedrige Index sind optional. Die nachfolgenden Beispiele sind alle gültig und resultieren in demselben Array-Typ:

```PASCAL
var
  Arr1: array[0..10] of string;
  Arr2: array[10] of string;
  Arr3: array[0..10];
  Arr4: array[10];
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="f826314d-c45d-40c8-bea1-f20d641b8a61" data-macro-name="code" id="bkmrk--26"></div>Skript-Arrays beginnen immer bei 0, wenn nicht eine andere Start-Zahl festgelegt worden sind.

Es existiert eine Skriptunterstützung für Array-Konstruktoren und Unterstützung auch für Varianten-Arrays. Zum Konstruieren ein Array, verwenden Sie die Zeichen "\[" und "\]". Sie können eine Array-Verschachtelung mit mehreren Indizes konstruieren. Sie können dann über Indizes auf Arrays zugreifen. Wenn ein Array aus mehreren Indizes besteht, trennen Sie die Indizes mit ",". Wenn Variable ein Varianten-Array ist, unterstützt das Skript automatisch die Indizierung in diesem variabel. Eine Variable ist ein Variantenarray, wenn sie über ein Array zugewiesen wurde. Konstruktor, wenn es eine direkte Referenz auf eine Delphi-Variable ist, die eine Variante ist Array oder wenn es mit VarArrayCreate erstellt wurde

```PASCAL
NewArray := [ 2,4,6,8 ];
Num:=NewArray[1]; //Num receives "4"
MultiArray := [ ['green','red','blue'] ,
['apple','orange','lemon'] ];
Str:=MultiArray[0,2]; //Str receives 'blue'
MultiArray[1,1]:='new orange';
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="ee138898-8968-46b2-83b2-9742d8253bbd" data-macro-name="code" id="bkmrk--27"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-confluence  delphi" id="bkmrk--59"></div></div></div></div>### Indexes

Strings, Arrays und Array-Eigenschaften können mit "\[" und "\]" Zeichen indiziert werden. Beispiel: Wenn Str eine Zeichenkettenvariable ist, gibt der Ausdruck Str\[3\] die dritte Zeichen in der durch Str bezeichneten Zeichenkette.

```PASCAL
MyChar:=MyStr[2];
MyStr[1]:='A';
MyArray[1,2]:=1530;
Lines.Strings[2]:='Some text';
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="c38b6cc8-a406-4039-89b0-a65789b2831b" data-macro-name="code" id="bkmrk--29"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-confluence  delphi" id="bkmrk--60"></div></div></div></div>## if-statements

Es gibt zwei Formen der if-Anweisung: if...then und die if...then...else. Wenn der if-Ausdruck wahr ist, wird die Anweisung (oder der Block) ausgeführt. Wenn es einen anderen Teil gibt und der Ausdruck falsch ist, wird die Anweisung (oder der Block) nach dem anderen ausführen.

```PASCAL
if J <> 0 then Result := I/J;
 
if J = 0 then Exit else Result := I/J;
 
if J <> 0 then
begin
  Result := I/J;
  Count := Count + 1;
end else
  Done := True;
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="da9ed82c-56e8-4d2c-bdec-652be4baa2cb" data-macro-name="code" id="bkmrk-1-2-3-4-5-6-7-8-9-10"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-confluence  delphi" id="bkmrk-1-2-3-4-5-6-7-8-9-10-5"></div></div></div></div>## while-statements

Eine while-Anweisung wird verwendet, um eine Anweisung oder einen Block zu wiederholen, während eine Bedingung (Ausdruck) als wahr ausgewertet wird. Die Kontrollbedingung wird ausgewertet vor der Anweisungsfolge. Wenn also die Bedingung bei der ersten Iteration falsch ist, wird die Anweisungsfolge nie ausgeführt. Die while-Anweisung führt ihre konstituierende Aussage (oder Block) wiederholt aus, solange der Ausdruck in der Iteration gültig bleibt.

```PASCAL
while Data[I] <> X do I := I + 1;
while I > 0 do
begin
  if Odd(I) then Z := Z * X;
  I := I div 2; 
  X := Sqr(X);
end;
 
while not Eof(InputFile) do
begin
  Readln(InputFile, Line);
  Process(Line);
end;
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="8dd47dc8-52b8-4d13-b4fa-e0e3ff9b8493" data-macro-name="code" id="bkmrk-1-2-3-4-5-6-7-8-9-10-0"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-confluence  delphi" id="bkmrk-1-2-3-4-5-6-7-8-9-10-6"></div></div></div></div>## repeat statements

Die Syntax einer Wiederholungserklärung ist Wiederholungserklärung1; ...; Erklärung; bis Ausdruck, wobei expression einen booleschen Wert zurückgibt. Die Wiederholungsanweisung führt seine Sequenz von konstituierenden Aussagen kontinuierlich aus und testet Ausdruck nach jeder Iteration. Wenn der Ausdruck True zurückgibt, wird die Wiederholung Anweisung beendet. Die Sequenz wird immer mindestens einmal ausgeführt, weil Ausdruck wird erst nach der ersten Iteration ausgewertet. Beispiele:

```PASCAL
repeat
  K := I mod J;
  I := J;
  J := K;
until J = 0;
 
repeat
  Write('Enter a value (0..9): ');
  Readln(I);
until (I >= 0) and (I <= 9);
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="b4e2d89a-0c71-4237-97ea-fbaee9c2f3fe" data-macro-name="code" id="bkmrk-1-2-3-4-5-6-7-8-9-10-1"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-confluence  delphi" id="bkmrk-1-2-3-4-5-6-7-8-9-10-7"></div></div></div></div>## for statements

Scripter unterstützt Anweisungen mit folgender Syntax:  
  
für Zähler :=initialValue bis finalValue  
 do-Anweisung  
  
Bei einer Anweisung, die den Zähler auf initialValue setzt, wird die Ausführung der Anweisung wiederholt (oder Block) und erhöhen den Wert des Zählers, bis der Zähler den Endwert erreicht hat.

```PASCAL
for c:=1 to 10 do
  a:=a+c;
 
for i:=a to b do
begin
  j:=i^2;
  sum:=sum+j;
end;
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="038b9765-5f19-4b94-afe2-4645e0044c77" data-macro-name="code" id="bkmrk-1-2-3-4-5-6-7-8-for%C2%A0"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-confluence  delphi" id="bkmrk-1-2-3-4-5-6-7-8-for%C2%A0-0"></div></div></div></div>## case-statements

Der Scripter unterstützt Fallanweisungen mit folgender Syntax:

```PASCAL
case selectorAusdruck von
 
  caseexpr1: Aussage1;
  ...
  caseexprn: Anweisung1; ..;
 
else
 
   elsestatement;
 
end
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="b0c27885-c808-48b7-85e1-6c4fec615e73" data-macro-name="code" id="bkmrk-case%C2%A0selectorausdruc"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-confluence nogutter  java" id="bkmrk-case%C2%A0selectorausdruc-0"></div></div></div></div>Wenn selectorAusruck mit dem Ergebnis eines der case-Ausdrücke übereinstimmt, wird die entsprechende Anweisung (oder der entsprechende Block) ausgeführt. Andernfalls wird das elsestatement ausgeführt. Ansonsten ist ein Teil der caseexprn-Anweisung optional. Anders als in Delphi muss die case-Anweisung im Skript nicht nur ordinale Werte verwenden. Sie können sowohl im Selektorausdruck als auch im Case-Ausdruck Ausdrücke beliebigen Typs verwenden. Beispiel:

```PASCAL
case uppercase(Fruit) of
   'lime': ShowMessage('green');
   'orange': ShowMessage('orange');
   'apple': ShowMessage('red');
else
   ShowMessage('black');
end;
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="2494c02f-06b9-4400-a31c-28936d80c8e2" data-macro-name="code" id="bkmrk-1-2-3-4-5-6-7-case%C2%A0u"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-confluence  delphi" id="bkmrk-1-2-3-4-5-6-7-case%C2%A0u-0"></div></div></div></div>## <span class="f_Heading1">function and procedure declaration</span>

<span class="f_Heading1">Die Deklaration von Funktionen und Prozeduren ist ähnlich wie bei Object Pascal in Delphi, mit dem Unterschied, dass man keine Variablentypen angibt. Genau wie bei OP verwenden Sie implizit deklarierte Ergebnisvariablen, um Funktionswerte zurückzugeben. Es können auch Parameter per Referenz verwendet werden, mit der erwähnten Einschränkung: es ist nicht notwendig, Variablentypen anzugeben. Für eine einfacher Lesbarkeit kann dies jedoch genutzt werden ergänzend zu einer Namensgebung, die den Ergebnis-Typ mit in den Funktionsnamen aufnimmt z.B. TodayAsString ,TodayAsDate ...</span>

```PASCAL
procedure HelloWord;
begin
   ShowMessage('Hello world!');
end;
  
procedure UpcaseMessage(Msg);
begin
   ShowMessage(Uppercase(Msg));
end;
  
function TodayAsString;
begin
   result:=DateToStr(Date);
end;
  
function Max(A,B);
begin
   if A>B then
      result:=A
   else
      result:=B;
end;
  
procedure SwapValues(var A, B);
Var Temp;
begin
   Temp:=A;
   A:=B;
   B:=Temp;
end;
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="d070bd65-9009-434e-9ceb-d9fcc530489d" data-macro-name="code" id="bkmrk-1-2-3-4-5-6-7-8-9-10-2"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-confluence  delphi" id="bkmrk-1-2-3-4-5-6-7-8-9-10-8"></div></div></div></div># <span class="f_Heading1">Script-based libraries</span>

Skript-basierte Bibliothek ist das Konzept, bei dem ein Skript andere Skripte "benutzen" kann (zum Aufruf von Prozeduren, zum Setzen globaler Variablen usw.).

Nehmen Sie zum Beispiel die folgenden Skripte:

```PASCAL
//Script 1
uses Script2;
  
begin
  Script2GlobalVar := 'Hello world!';
  ShowScript2Var;
end;
 
  
 
//Script2
var
  Script2GlobalVar: string;
  
procedure ShowScript2Var;
begin
  ShowMessage(Script2GlobalVar);
end;
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="7f762bca-f2f2-4e85-9d59-49e6752d5482" data-macro-name="code" id="bkmrk-1-2-3-4-5-6-7-8-9-10-3"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-confluence  delphi" id="bkmrk-1-2-3-4-5-6-7-8-9-10-9"></div></div></div></div>Wenn Sie das erste Skript ausführen, "benutzt" es Script2, und dann ist es in der Lage, globale Variablen zu lesen/schreiben und Prozeduren aus Script2 aufzurufen.

Das einzige Problem hier ist, dass Skript 1 "wissen" muss, wo es Skript2 finden kann.

Wenn der Compiler z.B. einen Bezeichner in der uses-Klausel erreicht, muss er wissen, wo es zu finden ist:

```PASCAL
uses Classes, Forms, Script2;
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="5fd61bbc-e08e-4c2c-83c7-f141b2f80848" data-macro-name="code" id="bkmrk--39"><div class="codeContent panelContent pdl"><div class="syntaxhighlighter sh-confluence nogutter  java">  
</div></div></div>Hier wird nun folgender Ablauf abgebildet, um die Bibliothek auf verschiedene Weise zu "laden":

1\. Er versucht, eine registrierte Delphi-basierte Bibliothek mit diesem Namen zu finden.

Mit anderen Worten, jede Bibliothek, die bei RegisterScripterLibrary registriert wurde. Dies gilt sowohl für die importierte VCL, die mit Scripter Studo bereitgestellt wird, als auch für die vom Import-Tool importierten Klassen. Dies ist der Fall für Klassen, Formulare und andere Einheiten.

2\. Versucht, ein Skript in der Scripts-Sammlung zu finden, bei dem UnitName mit dem Bibliotheksnamen übereinstimmt.

Jedes TatScript-Objekt in der Scripter.Scripts-Sammlung verfügt über eine UnitName-Eigenschaft. Sie können diese Eigenschaft manuell einstellen, so dass das Skript-Objekt in diesen Situationen wie eine Bibliothek behandelt wird. Im obigen Beispiel könnten Sie ein Skript-Objekt hinzufügen, seine SourceCode-Eigenschaft auf den Skript-2-Code setzen und dann UnitName auf 'Skript2' setzen. Auf diese Weise könnte das Skript1 das Skript2 als Bibliothek finden und seine Variablen und Funktionen verwenden.

3\. Versucht, eine Datei zu finden, deren Name mit dem Bibliotheksnamen übereinstimmt (wenn LibOptions.UseScriptFiles auf 'true' gesetzt ist)

Wenn LibOptions.UseScriptFiles auf true gesetzt ist, versucht der Skripter, die Bibliothek in Dateien zu finden. Wenn das Skript z. B. "uses Script2;" hat, sucht es nach Dateien mit dem Namen "Script2.psc".

# <span class="f_Heading1">Declaring classes in script (script-based classes)</span>

Es ist jetzt möglich, Klassen in einem Skript zu deklarieren. Mit dieser Funktion können Sie eine Klasse deklarieren, um sie auf ähnliche Weise wie in Delphi zu verwenden: Sie erstellen eine Instanz der Klasse und verwenden sie wieder.

Jede Klasse muss in einem separaten Skript deklariert werden, d.h. Sie müssen für jede zu deklarierende Klasse ein Skript haben.

Sie machen das Skript zu einem "Klassenskript", indem Sie die $CLASS-Direktive am Anfang des Skripts, gefolgt vom Klassennamen, hinzufügen:

```PASCAL
//Turn this script into a class script for TSomeClass
{$CLASS TSomeClass}
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="690161c6-97c6-4394-8209-c8c8b3b551ce" data-macro-name="code" id="bkmrk-1-2-%2F%2Fturn-this-scri"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-confluence  delphi" id="bkmrk-1-2-%2F%2Fturn-this-scri-0"></div></div></div></div>## Methoden und Eigenschaften

Jede in einem Klassenskript deklarierte globale Variable wird tatsächlich zu einer Eigenschaft der Klasse. Jede Prozedur/Funktion in einem Skript wird zu einer Klassenmethode.

Die Hauptroutine des Skripts wird immer dann ausgeführt, wenn eine neue Instanz der Klasse erzeugt wird, so dass sie als Klasseninitialisierer verwendet werden kann und Sie einige Eigenschaften auf Standardwerte setzen und eine ordnungsgemäße Klasseninitialisierung durchführen können.

```PASCAL
//My class script
{$CLASS TMyClass}
uses Dialogs;
  
var
  MyProperty: string;
  
procedure SomeMethod;
begin
  ShowMessage('Hello, world!');
end;
  
// class initializer
begin
  MyProperty := 'Default Value';
end;
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="037bd9ba-2407-4a82-a471-4803dd5e5427" data-macro-name="code" id="bkmrk-1-2-3-4-5-6-7-8-9-10-4"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-confluence  delphi" id="bkmrk-1-2-3-4-5-6-7-8-9-10-10"></div></div></div></div>## Nutzung der Klassen

Sie können die Klasse aus anderen Skripten heraus verwenden, indem Sie einfach eine neue Instanz der genannten Klasse erzeugen:Sie können die Klasse aus anderen Skripten heraus verwenden, indem Sie einfach eine neue Instanz der genannten Klasse erzeugen:

```PASCAL
uses MyClassScript;
var
  MyClass: TMyClass;
begin
  MyClass := TMyClass.Create;
  MyClass.MyProperty := 'test';
  MyClass.SomeMethod;
end;
```

<div class="code panel pdl conf-macro output-block" data-hasbody="true" data-macro-id="f043d6d2-c272-477d-aff5-86ea8d6ec897" data-macro-name="code" id="bkmrk-1-2-3-4-5-6-7-8-uses"><div class="codeContent panelContent pdl"><div><div class="syntaxhighlighter sh-confluence  delphi" id="bkmrk-1-2-3-4-5-6-7-8-uses-0"></div></div></div></div>## Einzelheiten der Implementierung

Die im Skript deklarierten Klassen sind "Pseudo"-Klassen. Das bedeutet, dass keine neuen Delphi-Klassen erstellt werden. Obwohl Sie z.B. in dem obigen Beispiel TMyClass.Create aufrufen, der Name "TMyClass" nur für das Skriptsystem bedeutet, gibt es keine Delphi-Klasse mit dem Namen TMyClass. Alle Objekte, die als skriptbasierte Klassen erstellt werden, sind eigentlich Instanzen der Klasse TScriptBaseObject. Sie können dieses Verhalten ändern, um Instanzen einer anderen Klasse zu erzeugen, aber diese neue Klasse muss von der Klasse TScriptBaseObject erben. Sie definieren die Basisklasse für alle "Pseudo"-Klassenobjekte in der Scripter-Eigenschaft ScriptBaseObjectClass.

## Speicherverwaltung

Obwohl Sie in Skripten die Methode Free aufrufen können, um Speicher freizugeben, der mit Instanzen von skriptbasierten Klassen verbunden ist, müssen Sie das nicht tun.

Alle in Skripten erstellten Objekte, die auf Skript-Klassen basieren, werden schließlich von der Skripter-Komponente zerstört.

## Einschränkungen

Da Scripter keine neuen echten Delphi-Klassen erstellt, gibt es einige Einschränkungen, was Sie damit machen können. Die wichtigste ist, dass Vererbung nicht unterstützt wird. Da alle Klassen in Skripter tatsächlich dieselbe Delphi-Klasse sind, können Sie keine Klassen erstellen, die von einer anderen Delphi-Klasse erben, außer der in der Klasse TScriptBaseObject deklarierten.

# Demo-Script

Hier ein sehr einfaches Script, was über alle Aktien iteriert und eine Ausgabe macht, wenn eine RIC\[isin\] Variable definiert wurde.

Dies ist nur eine Demo-Beispiel, zeigt aber relativ einfach die Funktionsweise. Idee des Scripts war es fehlerhaften Daten-Setups in Aktien zu finden und diese auch automatisch zu korrigieren.

```PASCAL
uses Common;

(* CreateDate: 10.03.2019
   Author: Jens Werschmoeller
   Required: Shareholder-Version ab 19.3.x (neue Object-Type-Definition notwendig) *)

procedure doSetup;
var lColumn: TListColumn;
begin
  varPanelProgress.Progress.CompletionSmooth:=true;

  (* BeginUpdate/EndUpdate sollte aus Performancegründen zwingend genutzt werden! *)
  varLog.BeginUpdate;
  varLog.Items.Clear;
  (* Header für das Logging passend vorbereiten *)
  varLog.Columns.Clear;
  lColumn:=varLog.Columns.Add; lColumn.Caption:='Name'; lColumn.Width:=350;
  lColumn:=varLog.Columns.Add; lColumn.Caption:='Alter Wert'; lColumn.Width:=200;
  lColumn:=varLog.Columns.Add; lColumn.Caption:='Neuer Wert'; lColumn.Width:=200;

  varLog.GroupView:=false;
  varLog.EndUpdate;
end;

(* Ziel: Automatische Korrektur der RIC-Einträge und gleichzeitig einfachstes Demo-Programm *)
procedure doRun( pIsSimulation: Boolean );
var lStock: TStock;
    lStockVar: TStockVariable;
    lLogItem: TListItem;

begin
    (* Log-Einträge werden über die varLog-Variable geschrieben, die vom Typ TAdvListView darstellt. Diese greift über .Items auf
       alle Log-Zeilen zu. In der Common-Bibliothek sind vereinfachte Methoden-Zugriffe möglich wie doLog *)

    varPanelProgress.Progress.Max:=varStocks.Count;
    varPanelProgress.Progress.Min:=1;
    varPanelProgress.Progress.ShowGradient:=true;

    (* Durchlauf alle Titel zur Prüfung *)
    for idxStock:=1 to varStocks.Count do if (varIsCanceled=false) then
    begin
      lStock:=varStocks.Items[idxStock-1];

      (* Zugriff auf den Fortschrittsbalken mit Aktualisierung auf die aktuelle Index-Position *)                                       
      varPanelProgress.Progress.Position:=idxStock;

      (* Aus Performancegründen wird nur bei jedem 500. Durchlauf überhaupt die Anzeige am Frontend aktualisiert *)
      if (idxStock mod 500=0) then
        varApplication.ProcessMessages;

      (* Zugriff entspricht itStock.StockVariables.ItemsName['RIC[isin]']; Über die ID ist es jedoch "stabiler" *)
      lStockVar:=lStock.StockVariables.ItemsNr[12];
      if (lStockVar<>nil) then
      begin
        (* Logging der Ergebnisse über die Hilfsmethode in der Common-Lib / siehe Reiter Gemeinsame Bibliothek *)
        itLogItem:=doLogAndCheck(lStock.Displayname+' ['+lStock.ISIN+'], '+lStock.Sector);
        itLogItem.SubItems.Add(lStockVar.Wert);

        (* Neue Wertzuweisungen der Variablen sind einfach möglich über itStockWert.Wert = ... *)
        itLogItem.SubItems.Add('-');
      end;
   end;                       
end;

begin
  doSetup;
  doRun( true );
end;
```

# Optionale Handelsstrategie-Parameter

[![image-1655631860873.png](https://www.shareholder24.com/wiki/uploads/images/gallery/2022-06/scaled-1680-/image-1655631860873.png)](https://www.shareholder24.com/wiki/uploads/images/gallery/2022-06/image-1655631860873.png)

Handelsstrategien können einfacher benutzt werden, wenn statt statischer Code-Anpassung beim Durchlauf einer Strategie eine Vorauswahl durch den Nutzer erfolgen kann. Hierfür ist eine "Optionale Auswahlbox" (s.o.) verfügbar gemacht, die in der Strategie selbst individuell initialisiert werden kann mit Werte und auch individuell ausgewertet werden kann. Beispiele hierfür sind:

- Anzeige und Auswahl aus den verfügbaren Watchlisten auf denen die Strategie angewendet werden soll
- Anzeige und Auswahl aus den verfügbaren Marktsegmenten auf denen die Strategie angewendet werden soll
- Auswahl eines Detail-Levels für die Anzeige z.B. Log-Info, Log-Error, Log-Details

Die Auswahlbox ist im Default leer und muss auch nicht benutzt werden. Um diese in der eigenen Strategie zu nutzen, muss lediglich eine SubRoutine "doInit" eingerichtet werden. Nachfolgend ein Beispiel für die Auswahl einer optionalen Watchliste:

## Initialisierungs-Routine "doInit" für die Auswahlbox

```PASCAL
procedure doInit;
begin
  varWatchlists.InitStrings( varParamCombobox.Items, true);
  varParamCombobox.Items.Insert(0,'Kein Watchlisten-Filter');
  varParamCombobox.ItemIndex:=0;
  varParamCombobox.Enabled:=true;
end;
```

## Nutzung der Nutzerauswahl in der Auswahlbox

```PASCAL
procedure doRun;
var fCheckWatchlist: TWatchlist;
begin
    varPanelStatus.Text:='Los gehts ... ';
    varPanelProgress.Progress.Max:=varStocks.Count;
    varPanelProgress.Progress.Min:=1;
    itLogItem:=nil;

    if (varParamCombobox.ItemIndex>=0) and (varParamCombobox.Items.Objects[varParamCombobox.ItemIndex]<>nil) then
      fCheckWatchlist:=varWatchlists.getItemWithName(varParamCombobox.Items[varParamCombobox.ItemIndex]) else
      fCheckWatchlist:=nil;

    for idxStock:=1 to varStocks.Count do if (varIsCanceled=false) then
    begin
      itStock:=varStocks.Items[idxStock-1];
      itBenchmarkStock:=varStocks.ItemISIN[getBenchmarkISIN];
      iPoints:=0;
      varPanelProgress.Progress.ShowGradient:=true;
      varPanelProgress.Progress.Position:=idxStock;
      if (idxStock mod 500=0) then
        varApplication.ProcessMessages;

      if (itStock.StockNetValues.Count>3) and
         (calcMarktkapitalisierung>0.01) and
         //(Segments.getAndToInternalNrAsBool(itStock.StockSegments, itSegment.Nr)) and
         ((fCheckWatchlist=nil) or (fCheckWatchlist.List.FindISIN(itStock.ISIN)))
      then
      begin



```

## Nutzung im Handelsstrategie-Studio

Im Studio steht die Auswahlbox für die Entwicklung ebenfalls zur Verfügung. Um die Routine zu starten, muss einmalig der Button "Initialisierung" aufgerufen werden. Die Hauptroutine (hier im doRun) sollte aber auch damit umgehen können, wenn die Auswahlbox leer ist d.h. varParamCombobox.Count=0 oder varParamCombobox.ItemIndex=-1 keine aktuelle Auswahl besitzt.

[![image-1655631869338.png](https://www.shareholder24.com/wiki/uploads/images/gallery/2022-06/scaled-1680-/image-1655631869338.png)](https://www.shareholder24.com/wiki/uploads/images/gallery/2022-06/image-1655631869338.png)

# Scripting für Indikatoren

Die folgenden Beispiele stehen auch im Scripting-Studio in der Profiversion zur Verfügung und ergeben nach Ausführung folgende Ergebnisse d,h. direkte Logausgabe im Scripting-Studio nach eigener Formatierung und im Watchlisten-Fenster die korrekte automatische Zuordnung und Erstellung der Titel.

[![image-1655631926345.png](https://www.shareholder24.com/wiki/uploads/images/gallery/2022-06/scaled-1680-/image-1655631926345.png)](https://www.shareholder24.com/wiki/uploads/images/gallery/2022-06/image-1655631926345.png)

[![image-1655631932351.png](https://www.shareholder24.com/wiki/uploads/images/gallery/2022-06/scaled-1680-/image-1655631932351.png)](https://www.shareholder24.com/wiki/uploads/images/gallery/2022-06/image-1655631932351.png)

```PASCAL
 uses Common;
(* CreateDate: 31.07.2014
   Author: Jens Werschmoeller
   Required: 13.4.18
   Ziel ist die Demonstration der Anwendung von Indikatoren. Hier am Beispiel
   am RSI-Indikator, wo eine Signalgenerierung abgefragt wird. Vorhandene
   Einstellungen werden dabei aus den Charteinstellungen übernommen, können
   aber auch per Parameter-Setup überschrieben werden
   Besonderheiten:
   - Der Indikator kann allein über die Konstante beim Aufruf CreateIndicatorWithType gewechselt werden
   - Der Ergebnistyp kann mit CalculateXXXX - Methoden zwischen Ergebniswert, Triggerwert, Aktivierungsgrad etc.
     jederzeit abgerufen werden
   - Es können aktiv Watchlisten manipuliert werden, hierzu wird über doSetup eine passende Watchliste, wenn
     notwendig angelegt und die gefundenen Titel hinzugefügt. Hierbei können dann auch beliebige Kommentare
     gesetzt werden
*)

(* Vorlagerte Variablendefinition ist nur für den Editor notwendig, damit diese erkannt werden und für
   die Autovervollständigung genutzt werden können *)
var
  itIndicator : TISignalindicator;
  itStock: TStock;
  itLogItem: TListItem;
  itWatchlist: TWatchlist;
  itWatchItem: TWatchListItem;
procedure doSetup;
begin
  {* Watchliste anlegen, wenn nicht vorhanden *}
  itWatchlist:=varWatchlists.FindOrCreate('Script-GD-Crossover');
  {* Alle vorhandenen Watchlisten-Einträge entfernen *}
  itWatchlist.List.Clear;
  (* Header für das Logging passend vorbereiten *)
  varLog.Column[1].Caption:='Indicator-Value';
  varLog.Column[1].Width:=200;
  varLog.Column[2].Caption:='Kursanzahl';
  varLog.Column[2].Width:=200;
  varLog.Column[3].Caption:='Signaltyp';
  varLog.Column[3].Width:=200;
end;
procedure doRun( indicatorTypeID: Integer);
var fSegment: TSegment;
begin
    varLog.BeginUpdate;
    varLog.Items.Clear;
    (* Durchlauf alle Titel zur Prüfung *)
    for idxStock:=1 to varStocks.Count     do
    begin
      itStock:=varStocks.Items[idxStock-1];
      (* Verwende nur Titel, die Deutsche Bank im Namen enthalten
         if (Pos('Deutsche Bank',itStock.Name)<>0) then
         if (Pos('DAX',varSegments.GetName( itStock.StockSegments ))<>0) then
         etc.
      *)
      if (itStock.Country='Deutschland') then
      begin
        (* Erzeuge den Indikator hier als den RSI-Indikator *)
        itIndicator:=varIndicators.CreateIndicatorWithTypeID(indicatorTypeID);
        (* Gebe dem Indikator die notwendigen Kursdaten des aktuellen Titels *)
        itIndicator.Kurse:=itStock.Kurs.createCache;
        (* Mittels Indicator.Parameter.Items[1].Wert:=10; könnten die Parameter
           des Indikators verändert werden. Die Bedeutung der Parameter muss pro
           Indikator nachgeschaut werden z.B. über Einstellungen / Indikatorengruppen / Doppelklick auf
           den Indikator *)
        (* Berechne die Ergebniswerte für das heutige Datum
           fValue:=itIndicator.CalculateValue(Trunc(Now()), itIndicator.Kurse);
        *)
        fValue:=itIndicator.CalculateErgActivation(Trunc(Now()), itIndicator.Kurse);
        (* Wenn ein Kauf/Verkaufssignal vorliegt, dann Logeintrag + Watch-Eintrag erzeugen *)
        if (fValue<>0) then
        begin
            (* Logging der Ergebnisse *)
            itLogItem:=doLogAndCheck(itStock.Displayname+' ['+itStock.ISIN+'], '+itStock.Sector);
            itLogItem.SubItems.Add(FloatToStr(fValue));
            if (itIndicator.Kurse<>nil) then
              itLogItem.SubItems.Add(InttoStr(itIndicator.Kurse.Count)) else
              itLogItem.SubItems.Add('-');
            if (fValue<0) then
              itLogItem.SubItems.Add('Verkaufssignal') else
              itLogItem.SubItems.Add('Kaufsignal');
            {* Watchlisteneintrag erzeugen *}
            itWatchItem:=TWatchListItem.Create(itStock);
            itWatchItem.CompareDate:=Now;
            if (fValue<0) then
              itWatchItem.Comment:='IndSignal:Verkaufssignal' else
              itWatchItem.Comment:='IndSignal:Kaufsignal';
            itWatchlist.List.Add(itWatchItem);
         end;
      end;
   end;
   varLog.EndUpdate;
end;
begin
  doSetup();
  doRun(cRSI);
end;
```

<div class="ms-editor-squiggler" id="bkmrk--2"></div>

# Logging in Scripten

Bereits in eines der ersten Beispiele integriert wurde das Logging in eine Standard-Debug-Ausgabe. Die hohe Flexibilität in der Darstellung des Loggings wird über eine Komponente von TMS-Software ermöglicht "TAdvListview".

[https://www.tmssoftware.com/alvdoc.htm#Properties](https://www.tmssoftware.com/alvdoc.htm#Properties)

Um die Funktionsweise möglichst einfach zu beschreiben hier konkret ein Beispiel aus eines der Standard-Beispielen:

[![image-1656157226426.png](https://www.shareholder24.com/wiki/uploads/images/gallery/2022-06/scaled-1680-/image-1656157226426.png)](https://www.shareholder24.com/wiki/uploads/images/gallery/2022-06/image-1656157226426.png)

Der dabei für verantwortliche Code ist sehr einfach für den Fall, dass ein Titel passend gefunden wurde. Die genutzten Variablen können (müssen aber nicht) zuvor definiert werden mit itLogItem: TAdvListItem; itStock und lSchillerKGV sind zuvor belegt worden im Programmcode und werden jetzt im Beispiel nur genutzt. itStock ist vom Typ TStock und besitzt daher dessen Eigenschaften. doLogAndCheck ist bereits in der Gemeinsamen Bibliothek angelegt und ist nachfolgend nur zur Vereinfachung dargestellt. Der Code kann natürlich aber auch jedesmal aufgenommen werden bzw. beliebig angepasst werden.

Siehe: [TStock](https://www.shareholder24.de/docs/class_t_stock.html)

```PASCAL
function doLogAndCheck( logMessage ): TListItem;
begin
  result:=varLog.Items.Add;
  with result as TListItem do
  begin
    Caption:=logMessage;
    checked:=true;
    groupID:=1;
  end;
end;
 
 
itLogItem:=doLogAndCheck(itStock.Displayname+' ['+itStock.ISIN+'], '+itStock.Sector);
itLogItem.subItems.Add('-');
itLogItem.subItems.Add(FloatToStr(lSchillerKGV));
```

Hier der zugehörige Code-Teil für die Darstellung jedes geprüften Titels. Die GroupID ordnet dabei der ersten optischen Gruppe (siehe Screenshot / zwei ein-ausklappbare Bereiche) diesen Logeintrag zu.Im ersten Beispiel (s.o.) wird dies mit groupID:=1 entsprechend der zweiten Gruppe zugeordnet.

```PASCAL
function doLog( logMessage): TListItem;
begin
  result:=varLog.Items.Add;
  with result as TListItem do
  begin
    Caption:=logMessage;
    groupID:=0;
  end;
end;
 
 
doLog(itStock.Displayname+'- Anzahl Jahre:'+intToStr(cntYears));


```

# Verfügbare Variablen und Datenstrukturen

<div class="table-wrap" id="bkmrk-variable-typ-referen"><table class="wrapped relative-table confluenceTable tablesorter tablesorter-default" role="grid" style="width: 126.667%;"><colgroup><col style="width: 2.47217%;"></col><col style="width: 15.8219%;"></col><col style="width: 11.0012%;"></col><col style="width: 22.7403%;"></col><col style="width: 47.9638%;"></col></colgroup><thead><tr class="tablesorter-headerRow" role="row"><th aria-disabled="false" aria-label=": No sort applied, activate to apply an ascending sort" aria-sort="none" class="numberingColumn confluenceTh tablesorter-header sortableHeader tablesorter-headerUnSorted" data-column="0" role="columnheader" scope="col" tabindex="0"><div class="tablesorter-header-inner">  
</div></th><th aria-disabled="false" aria-label="Variable: No sort applied, activate to apply an ascending sort" aria-sort="none" class="confluenceTh tablesorter-header sortableHeader tablesorter-headerUnSorted" data-column="1" role="columnheader" scope="col" tabindex="0"><div class="tablesorter-header-inner">Variable</div></th><th aria-disabled="false" aria-label="Typ-Referenz: No sort applied, activate to apply an ascending sort" aria-sort="none" class="confluenceTh tablesorter-header sortableHeader tablesorter-headerUnSorted" colspan="1" data-column="2" role="columnheader" scope="col" tabindex="0"><div class="tablesorter-header-inner">Typ-Referenz</div></th><th aria-disabled="false" aria-label="Hintergründe: No sort applied, activate to apply an ascending sort" aria-sort="none" class="confluenceTh tablesorter-header sortableHeader tablesorter-headerUnSorted" data-column="3" role="columnheader" scope="col" tabindex="0"><div class="tablesorter-header-inner">Hintergründe</div></th><th aria-disabled="false" aria-label="Beispiel-Zugriffe: No sort applied, activate to apply an ascending sort" aria-sort="none" class="confluenceTh tablesorter-header sortableHeader tablesorter-headerUnSorted" data-column="4" role="columnheader" scope="col" tabindex="0"><div class="tablesorter-header-inner">Beispiel-Zugriffe</div></th></tr></thead><tbody aria-live="polite" aria-relevant="all"><tr role="row"><td class="numberingColumn confluenceTd">1</td><td class="confluenceTd">varApplication</td><td class="confluenceTd" colspan="1">[TApplication](https://lazarus-ccr.sourceforge.io/docs/lcl/forms/tapplication.html)</td><td class="confluenceTd">Zugriff auf das Applikationsobjekt der Anwendung wie z.B.

- Application.ProcessMessages (Abarbeitung von UI-Refreshs)

</td><td class="confluenceTd">  
</td></tr><tr role="row"><td class="numberingColumn confluenceTd">2</td><td class="confluenceTd">varParamCombobox</td><td class="confluenceTd" colspan="1">TAdvOfficeComboBox</td><td class="confluenceTd">Zugriff auf eine Auswahlbox, die für den Nutzer angezeigt wird, um für das Script Auswahloptionen für den Nutzer zur Verfügung zu stellen. In der Susan-Levermann-Strategie wird über diese eine Liste der verfügbaren Watchlisten angezeigt und nutzbar gemacht. Für Nutzer der Strategie steht der entsprechende Source-Code zur Verfügung.  
z.B. für

- Watchlisten
- Depots
- Marktsegmente

</td><td class="confluenceTd">Auswahlbox für den Nutzer füllen mit allen Watchlisten-Einträgen, danach mit allen MarktSegment-Einträgen und final als ersten Eintrag (Index=0) "Kein-Watchlisten-Filter" einfügen.

```
varParamCombobox.Items.Clear;
for lIx:=1 to varWatchlists.Count do
    varParamCombobox.Items.AddObject('Watchliste: '+varWatchlists.Items[lIx-1].Displayname, varWatchlists.Items[lIx-1]);

for lIx:=1 to varSegments.Count do
   varParamCombobox.Items.AddObject('Markt: '+varSegments.Items[lIx-1].Displayname, varSegments.Items[lIx-1]);

varParamCombobox.Items.Insert(0,'Kein Watchlisten-Filter');
varParamCombobox.ItemIndex:=0;
varParamCombobox.Enabled:=true;
```

</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">3</td><td class="confluenceTd" colspan="1">varParamCheckbox</td><td class="confluenceTd" colspan="1">TAdvOfficeCheckBox</td><td class="confluenceTd" colspan="1">Zugriff auf eine Checkbox, die für den Nutzer angezeigt wird, um für das Script Auswahloptionen für den Nutzer zur Verfügung zu stellen. In der Susan-Levermann-Strategie wird diese für "Detaillierte Konfiguration" als Option genutzt.</td><td class="confluenceTd" colspan="1">Aktiviere überhaupt die Auswahlbox für den Nutzer. Im Standard wird die Auswahlbox überhaupt nicht angezeigt.  
Hinweis: Dies sollte vorzugsweise in einer "doInit-Methode" passieren.

```
  varParamCheckbox.Caption:='Frage Strategie-Parameter individuell ab ...';
  varParamCheckbox.Enabled:=true;
  varParamCheckbox.Visible:=true;
```

</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">4</td><td class="confluenceTd" colspan="1">varLog</td><td class="confluenceTd" colspan="1">TAdvListView</td><td class="confluenceTd" colspan="1">Die Primärausgabe erfolgt über das varLog-Objekt vom Typ TAdvListview. Es ist eine Komponente zur hierarchischen, gruppierten Tabellenausgabe von Informationen. Die Objekte besitzt Columns und eine GroupView-Eigenschaft zur automatischen Gruppierung von Einträgen.

Um ein neuen Log-Eintrag zu erzeugen, kann über varLog.Items.Add eine neue Zeile eingefügt werden. Das dabei zurückgegebene Objekt ist vom Typ TListItem, was eine Caption, eine GroupID, ImageIndex, Checked-Eigenschaft besitzt.

</td><td class="confluenceTd" colspan="1">Kopfzeile der Logausgabe gestalten:

```
(* BeginUpdate/EndUpdate sollte aus Performancegründen zwingend genutzt werden! *)
varLog.BeginUpdate;
varLog.Items.Clear;

(* Header für das Logging passend vorbereiten *)
varLog.Columns.Clear;
lColumn:=varLog.Columns.Add; lColumn.Caption:='Name'; lColumn.Width:=350;
lColumn:=varLog.Columns.Add; lColumn.Caption:='Alter Wert'; lColumn.Width:=200;
lColumn:=varLog.Columns.Add; lColumn.Caption:='Neuer Wert'; lColumn.Width:=200;

varLog.GroupView:=false;
varLog.EndUpdate;
```

Konkretes Logging:

```
function doLogWithOneSubMessage( logMessage, logSubMessage ): TListItem;
begin
  result:=varLog.Items.Add;
  with result as TListItem do
  begin
    Caption:=logMessage;
    subitems.add( logSubMessage );
    groupID:=0;
  end;
end;
```

Automatische Sortierung:

```
varLog.SortColumn:=pColumn+1;
varLog.SortDirection:=pSortDirection;
varLog.SortType:=3;
varLog.Sort;
```

</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">5</td><td class="confluenceTd" colspan="1">varPanelStatus</td><td class="confluenceTd" colspan="1">TAdvOfficeStatusPanel</td><td class="confluenceTd" colspan="1">Status-Updates für den Nutzer über die Statuszeile. Dabei können primär Textnachrichten über die varPanelStatus.Text Eigenschaft ausgegeben werden.-</td><td class="confluenceTd" colspan="1">  
</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">6</td><td class="confluenceTd" colspan="1">varPanelProgress</td><td class="confluenceTd" colspan="1">TAdvOfficeStatusPanel</td><td class="confluenceTd" colspan="1">Status-Updates für den Nutzer über die Statuszeile. Dabei liegt der Fokus auf der Fortschrittsanzeige.</td><td class="confluenceTd" colspan="1">```
varPanelProgress.Progress.Max:=varStocks.Count;
varPanelProgress.Progress.Min:=1;
varPanelProgress.Progress.ShowGradient:=true;
```

</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">7</td><td class="confluenceTd" colspan="1">varIsCanceled</td><td class="confluenceTd" colspan="1">Boolean</td><td class="confluenceTd" colspan="1">Der Nutzer kann ein Script in der Berechnung abbrechen. Dabei wird das Script nicht hart abgebrochen, sondern zunächst nur die Variable auf "true" gesetzt. Innerhalb des Scripts sollte diese daher immer abgefragt werden, um einen geordneten Abbruch zu realisieren.</td><td class="confluenceTd" colspan="1">Haupt-Iteration über alle Aktien, wobei aber bei jeder Iteration explizit die Abbruchsvariable "varIsCanceled" geprüft wird, um geordnet abzubrechen:

```
   (* Durchlauf alle Titel zur Prüfung *)
    for idxStock:=1 to varStocks.Count do if (not varIsCanceled) then
    begin
```

</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">8</td><td class="confluenceTd" colspan="1">varStocks</td><td class="confluenceTd" colspan="1">[TStocks](https://www.shareholder24.de/docs/class_t_stocks.html)</td><td class="confluenceTd" colspan="1">Zugriff auf alle Assets/Stocks in ShareHolder. Der Zugriff kann dabei sowohl lesend, als auch schreibend erfolgen. So können z.B. automatisiert Namensanpassungen vorgenommen werden.</td><td class="confluenceTd" colspan="1">Iteration über alle Stocks:

```
(* Durchlauf alle Titel zur Prüfung *)
 for idxStock:=1 to varStocks.Count do if (varIsCanceled=false) then
 begin
     itStock:=varStocks.Items[idxStock-1];
```

Zugriff auf Stock-Variablen, um diese automatisiert zu verändern:

```
(* Zugriff entspricht itStock.StockVariables.ItemsName['RIC[isin]']; Über die ID ist es jedoch "stabiler" *)

lStockVar:=lStock.StockVariables.ItemsNr[12];
if (lStockVar<>nil) then
   begin
...
```

</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">9</td><td class="confluenceTd" colspan="1">varIndicators</td><td class="confluenceTd" colspan="1">[TIndicatorGroups ](https://www.shareholder24.de/docs/class_t_indicator_groups.html)</td><td class="confluenceTd" colspan="1">Mittels Indicator.Parameter.Items\[1\].Wert:=10; könnten die Parameter des Indikators verändert werden. Die Bedeutung der Parameter muss pro Indikator nachgeschaut werden z.B. über Einstellungen / Indikatorengruppen / Doppelklick auf den Indikator.</td><td class="confluenceTd" colspan="1">```
   itIndicator:=varIndicators.CreateIndicatorWithTypeID(cRSL);

```

</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">10</td><td class="confluenceTd" colspan="1">varSegments</td><td class="confluenceTd" colspan="1">[TSegments ](https://www.shareholder24.de/docs/class_t_segments.html)</td><td class="confluenceTd" colspan="1">Zugriff auf alle Marktsegmente z.B. DAX, MDAX etc.</td><td class="confluenceTd" colspan="1">  
</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">11</td><td class="confluenceTd" colspan="1">varTransactions</td><td class="confluenceTd" colspan="1">[TTransactions ](https://www.shareholder24.de/docs/class_t_transactions.html)</td><td class="confluenceTd" colspan="1">  
</td><td class="confluenceTd" colspan="1">  
</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">12</td><td class="confluenceTd" colspan="1">varWatchlists</td><td class="confluenceTd" colspan="1">[TWatchlists](https://www.shareholder24.de/docs/class_t_watchlists.html)</td><td class="confluenceTd" colspan="1">Zugriff auf die internen Watchlisten. </td><td class="confluenceTd" colspan="1">Neue Watchliste erzeugen, wenn nicht zuvor angelegt mit dem Namen "Wa:ETF-Momentum-Sortlist"

```
if (fFirst) and (fUseSeparatWL) then
begin
  fWatchlist:=varWatchlists.FindOrCreate('Wa:ETF-Momentum-Sortlist');
  fWatchlist.Clear();
  fFirst:=false;
end;
```

Eintrag hinzufügen

```
if (fWatchlist<>nil) then
  begin
     if (not fUseSeparatWL) then
       fWatchItem:=fWatchlist.List.FindISIN(fItem.SubItems[pISINColumn]) else
     begin
       fWatchItem:=TWatchListItem.Create(itStock);
       fWatchlist.List.Add(fWatchItem);
     end;

     if (fWatchItem<>nil) then
     begin
        fWatchItem.CompareDate:=Now;
        //itWatchItem.Comment:='..';
        fWatchItem.PosNr:=StrToFloat(fItem.SubItems[pSumColumn]);
     end;
  end;
```

</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">13</td><td class="confluenceTd" colspan="1">varDepot</td><td class="confluenceTd" colspan="1">[TCalculatedDepotItems ](https://www.shareholder24.de/docs/class_t_calculated_depot_items.html)</td><td class="confluenceTd" colspan="1">Zugriff auf alle berechneten Depot-Positionen mit Stückzahl, gemittelten Preis, letzter Transaktion etc.</td><td class="confluenceTd" colspan="1">  
</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">14</td><td class="confluenceTd" colspan="1">varStops</td><td class="confluenceTd" colspan="1">[TStopRates](https://www.shareholder24.de/docs/class_t_stop_rates.html)</td><td class="confluenceTd" colspan="1">Zugriff auf alle definierten Stopps im Programm für Titel. Dabei enthält die Liste nur definierte Stopps d.h. Titel müssen keine Stopps haben. Stopps sind unabhängig von Depotpositionen.</td><td class="confluenceTd" colspan="1">  
</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">15</td><td class="confluenceTd" colspan="1">varProgramSettings</td><td class="confluenceTd" colspan="1">[TProgramSettings ](https://www.shareholder24.de/docs/class_t_program_settings.html)</td><td class="confluenceTd" colspan="1">Zugriff auf alle internen Programmeinstellungen wie Schriftgrößen, Kalkulationsbasis etc.</td><td class="confluenceTd" colspan="1">Verwende die offizielle Programmeinstellung für die KGV-Berechnung d.h. aktuelles Basisjahr (0), kommendes Jahr etc.

```
function calcPointsKGVRAW: Double;
begin
  Result:=itStock.KGV(varProgramSettings.ErgBasis);
end;
```

</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">16</td><td class="confluenceTd" colspan="1">varStockExchanges</td><td class="confluenceTd" colspan="1">[TStockExchanges](https://www.shareholder24.de/docs/class_t_stock_exchanges.html)</td><td class="confluenceTd" colspan="1">Zugriff auf die definierten Börsen wie F, Nasdaq, Xetra</td><td class="confluenceTd" colspan="1">  
</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">17</td><td class="confluenceTd" colspan="1">varINetVars</td><td class="confluenceTd" colspan="1">[TINetVars](https://www.shareholder24.de/docs/class_t_i_net_vars.html)</td><td class="confluenceTd" colspan="1">Zugriff auf die definierten Aktualisierungs-Internetvariablen</td><td class="confluenceTd" colspan="1">  
</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">18</td><td class="confluenceTd" colspan="1">varINetAddrs</td><td class="confluenceTd" colspan="1">[TINetAddrs](https://www.shareholder24.de/docs/class_t_i_net_addrs.html)</td><td class="confluenceTd" colspan="1">Zugriff auf die definierten Aktualisierungs-Internetadressen</td><td class="confluenceTd" colspan="1">  
</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">19</td><td class="confluenceTd" colspan="1">varAssets</td><td class="confluenceTd" colspan="1">[TAssets](https://www.shareholder24.de/docs/class_t_assets.html)</td><td class="confluenceTd" colspan="1">Zugriff auf die definierten Asset-Klassen</td><td class="confluenceTd" colspan="1">  
</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">20</td><td class="confluenceTd" colspan="1">varStrategy</td><td class="confluenceTd" colspan="1">[TStrategy](https://www.shareholder24.de/docs/class_t_strategy.html)</td><td class="confluenceTd" colspan="1">Zugriff auf alle definierten Strategien</td><td class="confluenceTd" colspan="1">  
</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">21</td><td class="confluenceTd" colspan="1">varNNetze</td><td class="confluenceTd" colspan="1"><a rel="nofollow">TNets</a></td><td class="confluenceTd" colspan="1">Zugriff auf alle definierten Vorhersage-Modelle</td><td class="confluenceTd" colspan="1">  
</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">22</td><td class="confluenceTd" colspan="1">varAccounts</td><td class="confluenceTd" colspan="1">[TAccounts](https://www.shareholder24.de/docs/class_t_accounts.html)</td><td class="confluenceTd" colspan="1">Zugriff auf alle Konten</td><td class="confluenceTd" colspan="1">  
</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">23</td><td class="confluenceTd" colspan="1">varImpFormate</td><td class="confluenceTd" colspan="1">[TImpFormats ](https://www.shareholder24.de/docs/class_t_imp_formats.html)</td><td class="confluenceTd" colspan="1">Zugriff auf alle Importformate</td><td class="confluenceTd" colspan="1">  
</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">24</td><td class="confluenceTd" colspan="1">varTradeMethods</td><td class="confluenceTd" colspan="1">[TTradeMethods](https://www.shareholder24.de/docs/class_t_trade_methods.html)</td><td class="confluenceTd" colspan="1">  
</td><td class="confluenceTd" colspan="1">  
</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">25</td><td class="confluenceTd" colspan="1">varAssessments</td><td class="confluenceTd" colspan="1">[TAssessments](https://www.shareholder24.de/docs/class_t_assessments.html)</td><td class="confluenceTd" colspan="1">  
</td><td class="confluenceTd" colspan="1">  
</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">26</td><td class="confluenceTd" colspan="1">varSparplaene</td><td class="confluenceTd" colspan="1">[TDepotSavingPlans ](https://www.shareholder24.de/docs/class_t_depot_saving_plans.html)</td><td class="confluenceTd" colspan="1">Zugriff auf die Sparpläne</td><td class="confluenceTd" colspan="1">  
</td></tr><tr role="row"><td class="numberingColumn confluenceTd" colspan="1">27</td><td class="confluenceTd" colspan="1">varINetUpdateGroups</td><td class="confluenceTd" colspan="1">[TINetUpdateGroups](https://www.shareholder24.de/docs/class_t_i_net_update_groups.html)</td><td class="confluenceTd" colspan="1">Zugriff auf die Kursaktualisierungsgruppen</td><td class="confluenceTd" colspan="1">  
</td></tr></tbody></table>

</div>## Registrierung von Variablen und Kontext im Detail für das Scripting-Studio

Version 19.3.2

```PASCAL
 with Scripter do
  begin
    LibOptions.SearchPath.Add(IDEEngine.BasePath);
    LibOptions.SourceFileExt := '.script';
    LibOptions.CompiledFileExt := '.psc';

    Scripter.OptionExplicit := false;
    logList.Items.Clear;
    Scripter.AddObject('varApplication', Application);
    Scripter.AddObject('varParamCombobox', fAdvCombobox);
    Scripter.AddObject('varParamCheckbox', fAdvCheckbox);


    Scripter.DefineClassByRTTI(TApplication);
    Scripter.DefineClassByRTTI(TBasisobject); // ,roInclude,false,'TBasisObject',[mvPublic,mvPublished]
    Scripter.DefineClassByRTTI(TAdvListView);
    Scripter.DefineClassByRTTI(TListItems);
    Scripter.DefineClassByRTTI(TStrings);
    Scripter.DefineClassByRTTI(TListItem);
    Scripter.DefineClassByRTTI(TListGroup);
    Scripter.DefineClassByRTTI(TListGroups);
    Scripter.DefineClassByRTTI(TStringList);


    Scripter.AddObject('varLog', flogList);
    Scripter.DefineClassByRTTI(TListColumns);
    Scripter.DefineClassByRTTI(TListColumn);
    Scripter.AddObject('varPanelStatus', fStatusPanel);
    Scripter.AddObject('varPanelProgress', fProgressPanel);
    Scripter.AddVariable('varIsCanceled', fIsCanceled);

    Scripter.DefineClassByRTTI(TStocks);
    Scripter.DefineClassByRTTI(TAsset);
    Scripter.DefineClassByRTTI(TAssets);
    Scripter.DefineClassByRTTI(TAutoImports);
    Scripter.DefineClassByRTTI(TCalculatedDepotAccount);
    Scripter.DefineClassByRTTI(TCalculatedDepotAccounts);
    Scripter.DefineClassByRTTI(TCalculatedDepotItem);
    Scripter.DefineClassByRTTI(TCalculatedDepotItems);
    Scripter.DefineClassByRTTI(TCandle);
    Scripter.DefineClassByRTTI(TCandleFormation);
    Scripter.DefineClassByRTTI(TChartindicator);
    Scripter.DefineClassByRTTI(TDepotSavingPlan);
    Scripter.DefineClassByRTTI(TDepotSavingPlans);
    Scripter.DefineClassByRTTI(TDynamicFilter);
    Scripter.DefineClassByRTTI(TDynamicFilterCondition);
    Scripter.DefineClassByRTTI(TDynamicFilterConditions);
    Scripter.DefineClassByRTTI(TDynamicFilterConditionTree);
    Scripter.DefineClassByRTTI(TDynamicFilterConditionTrees);
    Scripter.DefineClassByRTTI(TDynamicFilterResult);
    Scripter.DefineClassByRTTI(TDynamicFilterResults);
    Scripter.DefineClassByRTTI(TDynamicFilters);
    Scripter.DefineClassByRTTI(TEnhancedList);
    Scripter.DefineClassByRTTI(TFilterTaipan);
    Scripter.DefineClassByRTTI(TFilterTaipanItem);
    Scripter.DefineClassByRTTI(THelperAverage);
    Scripter.DefineClassByRTTI(THTMLParser);
    Scripter.DefineClassByRTTI(TIAroon);
    Scripter.DefineClassByRTTI(TIBollinger);
    Scripter.DefineClassByRTTI(TICandleFormationen);
    Scripter.DefineClassByRTTI(TICandleFormationenCache);
    Scripter.DefineClassByRTTI(TICCI);
    Scripter.DefineClassByRTTI(TIChaikin);
    Scripter.DefineClassByRTTI(TICoppock);
    Scripter.DefineClassByRTTI(TIDMI);
    Scripter.DefineClassByRTTI(TIDSStochastik);
    Scripter.DefineClassByRTTI(TIForceIndex);
    Scripter.DefineClassByRTTI(TIGDEMA);
    Scripter.DefineClassByRTTI(TIGDUmsatz);
    Scripter.DefineClassByRTTI(TIHistVol);
    Scripter.DefineClassByRTTI(TIMACD);
    Scripter.DefineClassByRTTI(TIMFI);
    Scripter.DefineClassByRTTI(TIMomentum);
    Scripter.DefineClassByRTTI(TImpFormat);
    Scripter.DefineClassByRTTI(TImpFormats);
    Scripter.DefineClassByRTTI(TIndicator);
    Scripter.DefineClassByRTTI(TIndicatorGroup);
    Scripter.DefineClassByRTTI(TIndicatorGroups);
    Scripter.DefineClassByRTTI(TIndicatorParam);
    Scripter.DefineClassByRTTI(TIndicatorParams);
    Scripter.DefineClassByRTTI(TIndicatorSignals);
    Scripter.DefineClassByRTTI(TINegativeVolumeIndex);
    Scripter.DefineClassByRTTI(TInetAddr);
    Scripter.DefineClassByRTTI(TINetAddrs);
    Scripter.DefineClassByRTTI(TINetUpdateGroup);
    Scripter.DefineClassByRTTI(TINetUpdateGroups);
    Scripter.DefineClassByRTTI(TINetVar);
    Scripter.DefineClassByRTTI(TINetVars);
    Scripter.DefineClassByRTTI(TINewHigh);
    Scripter.DefineClassByRTTI(TINewLow);
    Scripter.DefineClassByRTTI(TINNKorrelation);
    Scripter.DefineClassByRTTI(TINNPrognose);
    Scripter.DefineClassByRTTI(TInternetProperties);
    Scripter.DefineClassByRTTI(TIntSignalIndicatorCache);
    Scripter.DefineClassByRTTI(TIOnBalanceVolume);
    Scripter.DefineClassByRTTI(TIPFE);
    Scripter.DefineClassByRTTI(TIPositiveVolumeIndex);
    Scripter.DefineClassByRTTI(TIPSAR);
    Scripter.DefineClassByRTTI(TIPvt);
    Scripter.DefineClassByRTTI(TIRAVI);
    Scripter.DefineClassByRTTI(TIRMI);
    Scripter.DefineClassByRTTI(TIRSI);
    Scripter.DefineClassByRTTI(TIRSL);
    Scripter.DefineClassByRTTI(TIRWI);
    Scripter.DefineClassByRTTI(TISignalIndicator);
    Scripter.DefineClassByRTTI(TISignalIndicatorCache);
    Scripter.DefineClassByRTTI(TISignalIndicators);
    Scripter.DefineClassByRTTI(TIStdDev);
    Scripter.DefineClassByRTTI(TIStochastik);
    Scripter.DefineClassByRTTI(TITrix);
    Scripter.DefineClassByRTTI(TITRWinkel);
    Scripter.DefineClassByRTTI(TITSF);
    Scripter.DefineClassByRTTI(TIVHF);
    Scripter.DefineClassByRTTI(TIVolumeNotis);
    Scripter.DefineClassByRTTI(TIVolumePriceTrend);
    Scripter.DefineClassByRTTI(TIWilderVol);
    Scripter.DefineClassByRTTI(TParamEnhancedList);
    Scripter.DefineClassByRTTI(TProfitStop);
    Scripter.DefineClassByRTTI(TProgramSettings);
    Scripter.DefineClassByRTTI(TProperties);
    Scripter.DefineClassByRTTI(TSegment);
    Scripter.DefineClassByRTTI(TSegments);
    Scripter.DefineClassByRTTI(TSignalItem);
    Scripter.DefineClassByRTTI(TSplit);
    Scripter.DefineClassByRTTI(TSplits);
    Scripter.DefineClassByRTTI(TStock);
    Scripter.DefineClassByRTTI(TStockExchange);
    Scripter.DefineClassByRTTI(TStockExchanges);
    Scripter.DefineClassByRTTI(TStockNetValue);
    Scripter.DefineClassByRTTI(TStockNetValues);
    Scripter.DefineClassByRTTI(TStockNews);
    Scripter.DefineClassByRTTI(TStockNewsList);
    Scripter.DefineClassByRTTI(TStockProfile);
    Scripter.DefineClassByRTTI(TStockProfiles);
    Scripter.DefineClassByRTTI(TStocks);
    Scripter.DefineClassByRTTI(TStockVariable);
    Scripter.DefineClassByRTTI(TStockVariables);
    Scripter.DefineClassByRTTI(TStopRate);
    Scripter.DefineClassByRTTI(TStopRates);
    Scripter.DefineClassByRTTI(TStrategy);
    Scripter.DefineClassByRTTI(TStringParser);
    Scripter.DefineClassByRTTI(TTaipanCatalogItem);
    Scripter.DefineClassByRTTI(TTaipanCatalogItems);
    Scripter.DefineClassByRTTI(TTradeMethod);
    Scripter.DefineClassByRTTI(TTradeMethods);
    Scripter.DefineClassByRTTI(TTradingSystem);
    Scripter.DefineClassByRTTI(TTradingSystemMetricHelper);
    Scripter.DefineClassByRTTI(TTradingSystemMetrics);
    Scripter.DefineClassByRTTI(TTradingSystemThread);
    Scripter.DefineClassByRTTI(TTradingSystemTrades);
    Scripter.DefineClassByRTTI(TTrailingStop);
    Scripter.DefineClassByRTTI(TWatchlist);
    Scripter.DefineClassByRTTI(TWatchlistItem);
    Scripter.DefineClassByRTTI(TWatchlistItems);
    Scripter.DefineClassByRTTI(TWatchlists);
    Scripter.DefineClassByRTTI(THistoryItem);
    Scripter.DefineClassByRTTI(TKurse);
    Scripter.AddObject('varStocks', Stocks);

    Scripter.AddConstant('ctTrendfolger', ctTrendfolger);
    Scripter.AddConstant('typMA', typMA);
    Scripter.AddConstant('cRMI', cRMI);
    Scripter.AddConstant('cCandlesticks', cCandlesticks);
    Scripter.AddConstant('cMA', cMA);
    Scripter.AddConstant('cBollinger', cBollinger);
    Scripter.AddConstant('cPSAR', cPSAR);
    Scripter.AddConstant('cGDUmsatz', cGDUmsatz);
    Scripter.AddConstant('cMomentum', cMomentum);
    Scripter.AddConstant('cRSI', cRSI);
    Scripter.AddConstant('cStochastik', cStochastik);
    Scripter.AddConstant('cChaikin', cChaikin);
    Scripter.AddConstant('cDSStochastik', cDSStochastik);
    Scripter.AddConstant('cMFI', cMFI);
    Scripter.AddConstant('cCoppock', cCoppock);
    Scripter.AddConstant('cRSL', cRSL);
    Scripter.AddConstant('cMACD', cMACD);
    Scripter.AddConstant('cTRIX', cTRIX);
    Scripter.AddConstant('cCCI', cCCI);
    Scripter.AddConstant('cRMI', cRMI);
    Scripter.AddConstant('cPFE', cPFE);
    Scripter.AddConstant('cTSF', cTSF);
    Scripter.AddConstant('cPVT', cPVT);
    Scripter.AddConstant('cNewHigh', cNewHigh);
    Scripter.AddConstant('cNewLow', cNewLow);
    Scripter.AddConstant('cStdDev', cStdDev);
    Scripter.AddConstant('cHistVol', cHistVol);
    Scripter.AddConstant('cVHF', cVHF);
    Scripter.AddConstant('cWilderVOl', cWilderVOl);
    Scripter.AddConstant('cADX', cADX);
    Scripter.AddConstant('cRAVI', cRAVI);
    Scripter.AddConstant('cTRWinkel', cTRWinkel);
    Scripter.AddConstant('cRWI', cRWI);
    Scripter.AddConstant('cAroon', cAroon);
    Scripter.AddConstant('cNNKorrelation', cNNKorrelation);
    Scripter.AddConstant('cNNPrognose', cNNPrognose);
    Scripter.AddConstant('cForceIndex', cForceIndex);
    Scripter.AddConstant('cOnBalanceVolume', cOnBalanceVolume);
    Scripter.AddConstant('cVolumePriceTrend', cVolumePriceTrend);
    Scripter.AddConstant('cNegativeVolumeIndex', cNegativeVolumeIndex);
    Scripter.AddConstant('cPositivVolumeIndex', cPositivVolumeIndex);
    Scripter.AddConstant('cVolumeNotisV', cVolumeNotisV);

    Scripter.DefineClassByRTTI(TIndicator);
    Scripter.DefineClassByRTTI(TChartindicator);
    Scripter.DefineClassByRTTI(TISignalIndicator);
    Scripter.DefineClassByRTTI(TIRMI);
    Scripter.DefineClassByRTTI(TIndicatorGroups);
    Scripter.DefineClassByRTTI(TIndicatorParams);
    Scripter.DefineClassByRTTI(TIndicatorParam);
    Scripter.DefineClassByRTTI(TIndicatorSignals);
    Scripter.AddObject('varIndicators', IndicatorGroups);

    Scripter.DefineClassByRTTI(TSegments);
    Scripter.DefineClassByRTTI(TSegment);
    Scripter.AddObject('varSegments', Segments);

    Scripter.DefineClassByRTTI(TTransaction);
    Scripter.DefineClassByRTTI(TTransactions);
    Scripter.DefineClassByRTTI(TAssessments);
    Scripter.AddObject('varTransactions', Transactions);


    Scripter.DefineClassByRTTI(TWatchlist);
    Scripter.DefineClassByRTTI(TWatchlists);
    Scripter.DefineClassByRTTI(TWatchlistItems);
    Scripter.DefineClassByRTTI(TWatchlistItem);
    Scripter.AddObject('varWatchlists', Watchlists);

    Scripter.DefineClassByRTTI(TCalculatedDepotItems);
    Scripter.DefineClassByRTTI(TCalculatedDepotItem);
    Scripter.AddObject('varDepot', CalculatedDepotItems);
    Scripter.DefineClassByRTTI(TStoprate);
    Scripter.AddObject('varStops', StopRates);
    Scripter.AddObject('varProgramSettings', ProgramSettings);

    Scripter.AddObject('varStockExchanges', StockExchanges);
    Scripter.AddObject('varINetVars', INetVars);
    Scripter.AddObject('varINetAddrs', INetAddrs);
    Scripter.AddObject('varAssets', Assets);
    Scripter.AddObject('varStrategy', Strategy);
    Scripter.AddObject('varNNetze', NNetze);
    Scripter.AddObject('varAccounts', Accounts);
    Scripter.AddObject('varImpFormate', ImpFormate);
    Scripter.AddObject('varTradeMethods', TradeMethods);
    Scripter.AddObject('varAssessments', Assessments);
    Scripter.AddObject('varSparplaene', Sparplaene);
    Scripter.AddObject('varINetUpdateGroups', INetUpdateGroups);
  end;
```

Alle TAdv\* Objekte sind genauer durch den Komponentenhersteller beschrieben und können aus Lizenzgründen auch von mir nicht genauer aufgegriffen werden.

Siehe hierzu unter: [https://www.tmssoftware.com/site/tmspack.asp](https://www.tmssoftware.com/site/tmspack.asp)

# Automatische Stammdaten-Korrektur-Script als Beispiel

Use-Case- Alle Titel entweder exklusiv oder zusätzlich dem Archiv zuordnen.

```PASCAL
uses Common;

procedure doSetup
begin
  ...
end;

procedure doRun;
var litStock     : TStock;
var lArchiveSegment: TSegment;
var lArchiveSegmentBitMask: TBitmask;

begin
  (* Alle Werte in Archiv. *)
  lArchiveSegment:=varSegments.ItemsName['Archiv'];
  lArchiveSegmentBitMask:=lArchiveSegment.getNrAsBitMask;
  for idxStock:=1 to varStocks.Count do
  begin
    litStock:=varStocks.Items[idxStock-1];
    if (varSegments.getAndToInternalNrAsBool( litStock.StockSegments, lArchiveSegmentBitMask)) then
    begin
      (* Alle Werte zusätzlich dem Archiv zuordnen *)
      litStock.StockSegments:=varSegments.getORToInternalNr( litStock.StockSegments, lArchiveSegmentBitMask);
      (* oder exklusiv d.h. alle Werte nur ins Archiv verschieben
         itStock.StockSegments:=lArchiveSegmentBitMask;
      *)               
    end;
  end;
end;

begin                              
  doSetup();
  doRun();             
end;


```

Ab der 21.6.x Version werden die Markt und Watchlisten-Zuordnungen über Bitmasken zugeordnet.  
  
Diese sind vom Typ TBitmask:

type  
 TBitmask = record  
 BitFields: Array\[1..8\] of UInt64;

 const MaxFields = 8;  
 const MaxBit = MaxFields\*64-1;

 class operator Add(const v1, v2: TBitmask): TBitmask;  
 class operator Equal(const v1, v2: TBitmask): Boolean;  
 class operator NotEqual(const v1, v2: TBitmask): Boolean;

 end align 16;

Das komplette Zurücksetzen eines Titels kann damit mit folgender Konstante erfolgen:  
const cZeroBitmask : TBitmask = ( Bitfields: (0,0,0,0,0,0,0,0) );

Beispielzuordnungen als Konstante sind z.B.  
 cEuroStoxx50: TBitmask = (Bitfields: (16,0,0,0,0,0,0,0));  
 cNasdaq : TBitmask = (Bitfields: (1 shl 12,0,0,0,0,0,0,0));

Folgende Methoden für alle von TEnhancedList abgegleiteten Klassen z.B. TSegments, TWatchlists, TStocks stehen zur Verfügung:

```PASCAL
    class function getORToInternalNr(orValue, Nr: TBitmask): TBitmask;
    class function getORToNr(orValue, Nr: Int64): Int64;


    class function getXORToInternalNr(xorValue, Nr: TBitmask): TBitmask;
    class function getAndToInternalNr(andValue, Nr: TBitmask): TBitmask;

    class function getAndToInternalNrAsBool(andValue, Nr: TBitmask): Boolean;
    class function getAndToNrAsBool(andValue, Nr: Int64): Boolean;

    class function getAndNotToInternalNr(Nr, andNotValue: TBitmask): TBitmask;


```

An den Objektklassen selbst stehen zur Umrechnung immer zur Verfügung:

```PASCAL
    function PrimaryKeyID: Int64; virtual;
    function getNrAsBitMask: TBitmask;
    class function convertBitFieldToMask( Nr: Int64 ): TBitmask;
    class function convertToMask( Nr: Int64 ): TBitmask;
```

# Scripting-Studio-Editor und Bedienung

[![image-1655632187395.png](https://www.shareholder24.com/wiki/uploads/images/gallery/2022-06/scaled-1680-/image-1655632187395.png)](https://www.shareholder24.com/wiki/uploads/images/gallery/2022-06/image-1655632187395.png)

## (1) Auswahl des aktiven Scriptes

Es werden beim Laden eines Filter immer gleichzeitig drei Skripte geladen, um das spätere Handling deutlich zu vereinfachen:

<div class="table-wrap" id="bkmrk-speicherung-unter-ti"><table class="wrapped confluenceTable tablesorter tablesorter-default" role="grid"><thead><tr class="tablesorter-headerRow" role="row"><th aria-disabled="false" aria-label="Speicherung unter: No sort applied, activate to apply an ascending sort" aria-sort="none" class="confluenceTh tablesorter-header sortableHeader tablesorter-headerUnSorted" data-column="0" role="columnheader" scope="col" tabindex="0"><div class="tablesorter-header-inner">Speicherung unter</div></th><th aria-disabled="false" aria-label="Titel: No sort applied, activate to apply an ascending sort" aria-sort="none" class="confluenceTh tablesorter-header sortableHeader tablesorter-headerUnSorted" data-column="1" role="columnheader" scope="col" tabindex="0"><div class="tablesorter-header-inner">Titel</div></th><th aria-disabled="false" aria-label="Zielstellung: No sort applied, activate to apply an ascending sort" aria-sort="none" class="confluenceTh tablesorter-header sortableHeader tablesorter-headerUnSorted" colspan="1" data-column="2" role="columnheader" scope="col" tabindex="0"><div class="tablesorter-header-inner">Zielstellung</div></th><th aria-disabled="false" aria-label="Sichtbarkeit: No sort applied, activate to apply an ascending sort" aria-sort="none" class="confluenceTh tablesorter-header sortableHeader tablesorter-headerUnSorted" colspan="1" data-column="3" role="columnheader" scope="col" tabindex="0"><div class="tablesorter-header-inner">Sichtbarkeit</div></th></tr></thead><tbody aria-live="polite" aria-relevant="all"><tr role="row"><td class="confluenceTd">\\Daten\\Scripts\\&lt;Name&gt;.script</td><td class="confluenceTd">Aktiver Filter</td><td class="confluenceTd" colspan="1">Produktiver Filter</td><td class="confluenceTd" colspan="1">Ja (ab 2.6) in den Filtermasken im Frontend außerhalb des Scripting-Studios</td></tr><tr role="row"><td class="confluenceTd" colspan="1">\\Daten\\Scripts\\&lt;Name&gt;.script-dev</td><td class="confluenceTd" colspan="1">Aktiver Filter ("Spielwiese")</td><td class="confluenceTd" colspan="1">Test/Entwicklungsversion des produktiven Filters für Weiterentwicklungen, ohne den produktiven "Filter" kaputt zu entwickeln. Jeder Filter besitzt immer einen produktive und eine Entwicklungs(Sandbox)-Version. Eine Entwicklungsversion kann zur Produktiv-Version gemacht werden (wird hier kopiert) über das Hauptmenü "Projekte / Entwicklungsversion live nehmen".</td><td class="confluenceTd" colspan="1">Nein nur im Scripting-Studio</td></tr><tr role="row"><td class="confluenceTd" colspan="1">\\Daten\\Scripts\\Common.script</td><td class="confluenceTd" colspan="1">Gemeinsame Bibliothek</td><td class="confluenceTd" colspan="1">Hier sollte gemeinsam genutzte Funktionen und Hilfsroutinen ausgelagert werden, um effektiv in allen Filter zu arbeiten und Redundanzen zu vermeiden. Da auch das gegenseitige Einbinden der Standard-Scripte erlaubt ist, dient diese Sonderbehandlung aber der Effizienzsteigerung, um hier gezielte wiederverwendbare Funktionen und Procedures zu verlagern, um die eigentlichen Filter schlank und effizient zu halten.</td><td class="confluenceTd" colspan="1">Nein nur im Scripting-Studio</td></tr><tr role="row"><td class="confluenceTd" colspan="1">\\Daten\\Scripts\\Common.script-dev</td><td class="confluenceTd" colspan="1">Gemeinsame Bibliothek ("Spielwiese")</td><td class="confluenceTd" colspan="1">Test/Entwicklungsversion der gemeinsam genutzten Bibliothek</td><td class="confluenceTd" colspan="1">Nein nur im Scripting-Studio</td></tr></tbody></table>

</div>### Hinweise zu Datensicherung und -Ablage

Da in Scripten sehr viel Zeit und Aufwand gesteckt werden kann, ist die Datensicherung nicht zu unterschätzen. Aktuell umgesetzt ist daher die Erstellung einer automatisches Backup-Version mit &lt;Name&gt;-backup-YYYYMMDD-HHMM bei jedem Speichervorgang (&lt;F2&gt;). Zu einem späteren Zeitpunkt ist auch die Synchronisation mit eigenen Dropbox-Instanzen vorgesehen. Aktuell werden diese Sicherungsdateien zu einem Script wieder gelöscht, wenn eine Script-Version "Verifiziert" wird (siehe Kontextmenü zu einem Filtereintrag (r.Maustaste über einen Filternamen)).

## (1a) Einstellungen

Unterhalb der Script-Auswahl findet sich ein kleines ein/ausklappbares Pannel "Einstellungen".

Für weitere Ausbaustufen wurde sofort ein Einstellungs-Grid angelegt, was praktisch unendlich fortgeführt werden kann durch seine Scrollfähigkeit. Beim Start sind nur wenige Einstellungen vorhanden:

- - Codebeispiele ausführbar: Dies bezieht sich auf die unter (4) gezeigten Code-Beispiele, die so beeinflusst werden. Im Standard sind die Beispiele nur als Hinweise für die abzubildende Mindeststruktur gedacht. Für die Sandbox ist es aber wahrscheinlich interessant auch lauffähige Codebeispiele zu haben. Die Einstellung wird geändert durch Klick in die Wert-Spalte, wo sich dann eine entsprechende Drop-Down-Box öffnet
    - Code-Folding nutzen: Im Programm können dann alle begin..end - Blöcke ein- und ausgeklappt werden. Dies erleichtert das Handling bei längeren Skripten.

## (2) Bibliotheks-Zugriff

Um die Entwicklung zu unterstützen werden zwei Grundkonzepte mit unterstützt:

- Unterscheidung zwischen Entwicklung (Sandbox) und aktuell produktivem Code
- Unterstützung von Bibliotheken insb. auch gemeinsam genutzter Bibliotheken zwischen den unterschiedlichen Scripten

Mit Wechsel zwischen den Reitern wird zwischen den verschiedenen dahinterliegenden Code-Fragmenten gewechselt.

## (3) Code

Hier befindet sich der Quelltexteditor der analog einem Notepad funktioniert mit den vorhandenen Tastenkombinationen (Strg-C-Kopieren, Strg-V-Einfügen etc.). Die Besonderheit ist hier, dass mit dem vorhandenen Code ein automatische Code-Highlighting erfolgt d.h. Schlüsselwörter oder Strukturen werden automatisch hervorgehoben in Schriftart und Form. So werden Kommentare beispielsweise immer kursiv/blau dargestellt.

Für die Entwicklung sind besonders folgende Funktionen relevant:

- Strg + "." zeigt die aktuell gültigen Funktionen/Konstanten/Variablen/Methoden an
- ( ) nach einer Procedure oder Funktion zeigt alle gültigen Werte an

Übergreifend unabhängig vom Quell-Code kann mit:

- F8 - Der Quellcode überprüft werden. Fehler werden in der Statusleiste direkt angezeigt und der Cursor springt automatisch zur Fehlerstelle
- F9 - Der Quellcode wird überprüft und danach ausgeführt. Im Datenverzeichnis wird im Erfolgsfall unter Unitname.PSC der übersetzte Quellcode angelegt und ab diesem Zeitpunkt kann dieser Filter als Bibliothek in anderen benutzt werden über "uses &lt;Unitname&gt;"

## (4) Ausgabe

Dies ist eigentlich eines der Highlights der Umsetzung und ist auch bisher nur eine erste Version, die spätere deutlich ausgebaut wird. Ziel ist es die Ergebnisse aus einem Filter-Lauf übersichtlich und performant und unmittelbar darzustellen.

Die Darstellung wird dabei durch den Code festgelegt d.h. welche Spalten, welcher Detaillierungsgrad, welche Sortierungen und welche Darstellungs-Gruppierungen genutzt werden sollen.

In der Ausgabe wird auf eine spezielle zugreifbare Komponente zugegriffen die folgende Eigenschaften unterstützt:

- Nutzung von Gruppen, um Ergebnisse im Filtervorgang zu gruppieren. Im Standard sind aktuell 3 Gruppen angelegt
- Ein/Ausklappen von Gruppen
- Nutzung von Checkbox-Markierungen
- Mehrspaltiges Layout, womit Informationen anders und strukturiert ausgegeben werden können

## (5) Sourcecode-Explorer

Der Source-Explorer versucht zeitnah synchron zum Quellcode die Struktur des Skriptes wiederzugeben, wobei unterschieden wird nach

- procedures: Alle Funktionen und Proceduren im Code, wobei Funktionen mit gelb markiert werden und proceduren mit grün
- uses: Alle eingebundenen Fremdbibliotheken. Dies kann die Common-Bibliothek sein (siehe (1)) oder alle anderen vorhandenen Skripte
- variables: Alle nicht lokalen Variablen (innerhalb einer procedure oder function definiert) werden hier gezeigt.

Mit Doppelklick auf einen Eintrag springt der Cursor automatisch an die zugehörige Programmcode-Position.

## (6) Code-Snippet-Beispiele zur Übernahme

Dies sind aktuell nicht erweiterbare Code-Beispiele (TODO: Pflege sollte außerhalb der IDE möglich sein und auch über Updates ermöglicht werden z.B. ScriptStudio.MOD).

Mit Doppelklick auf einen Eintrag wird das Codebeispiel übernommen. Aktuell existiert eine Einstellung unter (1), um die Beispiele entweder nur als Struktur oder lauffähig zu verwenden.