初心者のためのEasyLanguage入門(トレードステーション)
公開日:
:
株式自動売買開発 TradeStation, トレードステーション
目次/もくじ
これからトレードステーションのストラテジーを開発するためにEasyLanguageをやってみようという方向けの記事です。
イージーランゲージというだけあって、プログラム慣れている人ならなら ”サンプルを見ればだいたいわかるじゃん” というものばかりだと思います。
EasyLanguageのエディタ,コンパイル
TradeStationの「表示」から「EasyLanguage開発環境」を選択すると、下記のようなウィンドウが開きます。
これが開発エディタです。
F1を押すとヘルプが開くので、それを参考にしながら開発が可能です。(しかも日本語!)
コンパイル
「構築する」がコンパイルの代わりです。コンパイルに成功すると、”0エラー”と表示され、TradeStationでストラテジとして利用できるようになります。
サンプルコード
教科書的に説明されるよりも、サンプルコードがあった方がわかりやすいと思います。
サンプルのコードを開いてみましょう。「ファイル」ー>「開く」で適当なサンプルを開きます。
今回は移動平均線にしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
{ Search Tag: WA-Mov Avg 1 Line } inputs: Price( Close ) [DisplayName = "Price", ToolTip = "Enter an EasyLanguage expression to use in the moving average calculation."], Length( 9 ) [DisplayName = "Length", ToolTip = "Enter number of bars over which to calculate the simple moving average."], Displace( 0 ) [DisplayName = "Displace", ToolTip = "Displacement. Enter the number of bars by which plots will be displaced. Displacement may be positive (left) or negative (right)."] ; variables: Avg( 0 ) ; Avg = AverageFC( Price, Length ) ; if Displace >= 0 or CurrentBar > AbsValue( Displace ) then begin Plot1[Displace]( Avg, !( "Avg" ) ) ; { alert criteria } if AlertEnabled and Displace <= 0 then begin if Price crosses over Avg then Alert( !( "Price crossing over average" ) ) else if Price crosses under Avg then Alert( !( "Price crossing under average" ) ) ; end ; end ; |
ブロックと順番
まず、ストラテジには文のブロックがあり、宣言~売買文まであります。
文のブロックですが、これには順番があり、この順番を守る必要があります。
・インプット宣言文
・変数宣言文
・変数代入文
・プロット文: インジケーターの場合
・売買文: ストラテジーの場合
変数の宣言
変数の宣言は、数値の場合、
1 |
Variables: NumberVariables(0); |
のように後ろにかっこを付けて、中にデフォルトの数字を入れます。
複数ある場合は連続して宣言できます。
1 |
Vars: HalfPrevRange(0), HiBand(0), LoBand(0); |
bool型、真偽変数の場合は、後ろにtrueかfalseを入れます。
1 |
Variables: IsThisZombie(false); |
変数は大文字から始めてもOKです。
また、当たり前ですが、定義済み変数があり、
数値型は Value0 ~ Value99
bool型はCondition0 ~ Condition99
があります。
これらは宣言することなく、いつでも使えます。
文の種類
EasyLanguageには5種類の語があります。
• 予約語
予約語とはその名の通り EasyLanguage によって事前定義された意味を持っています。
Open、Close、Plot1、Buy 等があります。例えば、予約語 High は足の高値を意味します。
• 関数
関数は定義済みの式を EasyLanguage 文章に呼び出すことができる語です。Average、RSI、Lowest 等があります。
• ユーザー定義語
ユーザー定義語はユーザーが任意に作成した語です。ユーザー定義語は描画名、Input、Variables 等に使用されます。
• スキップ語
EasyLanguage の命令実行時にトレードステーションによって認識されない、可読性を上げるためだけに使用される語です。Of 、the、at 等があります。
• 属性
インジケーターやストラテジーの動作や計算ルールを設定するために使用される語です。LegacyColorValue、IntraBarOrkderGeneration 等があります。
ちなみに、予約語は比較的量があります。(884語あります。)とてもではないですが、覚えきれません。
基本的には自分が欲しい語だけ使えれば良いと思います。
コメントアウト
EasyLanguageの世界ではコメントは{}で行います。//でもコメントアウトされますが、例によって1行だけです。
開発環境下では予約語やテキスト文字などは色分けされるので、かなり見やすいと思います。
ここら辺も比較的洗練されていますね。
if文
コメントアウトに{}を使用する関係で、基本的な条件文には{}を使いません。
if文なんかは
1 |
if Displace >= 0 or CurrentBar > AbsValue( Displace ) then |
if…then…endのタイプです。
こういう面ではMQLやPHPやCよりもUWSCに近いですね。
1 2 3 4 5 6 7 8 |
if AlertEnabled and Displace <= 0 then <strong>begin</strong> if Price crosses over Avg then Alert( !( "Price crossing over average" ) ) else if Price crosses under Avg then Alert( !( "Price crossing under average" ) ) ; end ; end ; |
見慣れない予約語beginがありますが、リファレンスによると
Begin は、If…Then, If…Then…Else、For、または While ステートメントの後で複数行のコードを使用する場合のみ必要です。
各 Begin に対応する End がなければなりません。
要するに「if文の中が2行以上になる場合はbeginと書いてね」ということらしいです。
比較演算子
比較演算子はノットイコールと等価だけMQLと異なります。
1 2 3 4 5 6 |
< 左不等演算子 <= 等価左不等演算子 > 右不等演算子 >= 等価右不等演算子 = 等価演算子 <> 不等価演算子 |
==ではなく=です。
!=ではなく<>です。(>_<)
はい、それだけです。
かつ、または
&&条件は “and”
||条件は ”or”
で記述します。
for文
for文も使うことができます。
1 2 3 4 5 |
Variables: Sum(0), Counter(0); Sum = 0; For Counter = 0 To Length - 1 Begin Sum = Sum + Price[Counter]; End; |
加算ステップは1で固定みたいです。
トリッキーな使い方はできないですね。
同様にbreakも使えます。
1 2 3 4 5 6 |
For i = 0 to 9 Begin Print(i); If (i=4) then Break; End; |
配列、多次元配列の扱い
配列の宣言は、
1 |
Array: ArrayName(Value) ; |
でOKです。
複数宣言するときは
1 |
Array: ArrayName1(Value),ArrayName2(Value) ; |
でつなぐことができます。
また、固定長配列で宣言する場合は、
1 |
Array: int WeeklyHighs[52]; |
さらに、すべての配列に初期値を入れる場合は、
1 |
Array: int WeeklyHighs[52](0); |
でいけます。
EasyLanguageは多次元配列も可能なので、
1 |
Arrays: Volume123[5,20](0); |
のように宣言することもできます。[5][20]ではないので、ちょっとトリッキーです。
動的配列の場合は、
1 |
Array: int DynamicIntArray[](0) ; |
のように[]ないを空欄にすればOKです。
動的配列はインジケーターの作成時によく使っていましたが、Plot関数が優秀なので、必要ないような気もします。
動的配列を使おうとすると、比較的処理がややこしくなるので、
Array_Compare、Array_Copy、Array_GetMaxIndex、Array_GetType、Array_SetMaxIndex、Array_SetValRange、Array_Sort、Array_Sum
の関数と合わせて使う必要があります。
ここら辺は必要性を感じてからで良いでしょう。
—————————————————–
さて、今までは数値型変数の宣言時に型を省略していましたが、EasyLanguageでも整数型や浮動小数型があります。
例えば浮動小数で宣言する場合、
1 |
Var: DOUBLE MyVar1(1345.6097); |
整数で宣言する場合、
1 |
Var: INT MyVar1(120); |
bool型の場合、
1 |
Var: BOOL MyVar1(false); |
データ型は全部で、(float、double、int、bool、string、class)があります。
ちなみに、
変数の宣言時のvarは、Variable、Var、Vars、 Variablesでも同じです。(統一してくれよ)
変数名は最大 20 文字です。
変数名には、最大 20 の英数字に加えてピリオド (.) とアンダーライン (_) を含めることができます。
変数名を数字またはピリオド (.) で始めることはできません。
(変数名にピリオドが入っていたら、オブジェクト指向で書いているのか変数名なのか分かりにくくなると思うのは私だけでしょうか。ここら辺、他の言語の知識があると混乱します。)
時系列系予約語
自動売買ソフトを開発する上で重要なものとして、時系列系の予約語の把握があります。
今回はその予約語を紹介します。
1 |
CurrentTime |
使用しているコンピュータの時間に対応する EasyLanguage 時間 (HHMMフォーマット) を表す数値を返します。
HHMMフォーマットとは、 時時分分の表記ってことです。
例
午後5時18分なら1718、午前9時30分なら 0930 の値を返します。
時間と分が一緒になってしまうので、ちょっと使いづらいです。
1 |
Time |
現在の足の終値の EasyLanguage 時間 (HHMMフォーマット) を表す数式を返します。
例
足のTimeが午後4時の場合には1600、午前9時30分の場合には0930を返します。
つまり、CurrentTimeとTimeは一緒ですね。
1 |
DateTime |
DateTime は、倍精度小数値であり、ユリウス日と標準 Window 日付形式を使用した時間の組み合わせ (日.時間)DateTime の整数部分は日付部分 (1900 年を起点にしたもの) であり、小数部分はその日の経過時間 (午前 0 時を起点にしたもの) です。たとえば、11/01/2002 の12:00:00pm の足における DateTime プロパティの戻り値は、37561.50000となります。
うん、わかりにくい!
とりあえず整数部分は日付、小数部分はその日の経過秒ってことですね。1970年が起点ではなく1900年が起点というのは珍しいです。
1 |
Date |
分析されるバーの終値の EasyLanguage日付を表す数式を返します。YYYMMDD 形式です。
これ、年の表記がわかりにくく、
0 を 1900 年、100 を 2000 年として 103 は 2003 年を表しています。例えば、000 は 1900
年、088 は 1988 年です。
つまり、最初の数字が0の場合は1900,1の場合は2000代です。
1 |
EntryTime |
指定したポジションのエントリー時間を、時間制形式 HHMM で返します。
例
EntryTime(2) は、トヨタ自動車 株の日足チャートの 2 ポジション前のエントリー時刻として 1500 の値を返します。
1 |
EntryDateTime |
指定したストラテジーポジションのエントリー日付を、DateTime オブジェクトとして返します。
この関数は、ストラテジーの評価でのみ使用できます。入力を必要としませんが、入力 Num を使用することによって、以前のポジション (最大 10 ポジション前) から指定された値を取得できます。
例
EntryDateTime(2) は、2 ポジション前のエントリー日が 1998 年 10 月 5 日であった場合、981005 の値を返します。
これは決済ロジックの構築の際に必要ですね。
覚えておきましょう。
1 |
ExitTime |
指定したポジションの決済時間を、時間形式 HHMM で返します。
例
ExitTime(3) は、トヨタ自動車株の日中チャートの 3 ポジション前の終了時刻として 8500.0 の値を返します。
1 |
ExitDateTime |
指定したストラテジーポジションの決済日を、DateTime オブジェクトとして返します。
例
ExitDateTime(2) は、2 ポジション前の終了日付が 1998 年 10 月 22 日であった場合、981022 の値を返します。
1 |
TradeTime |
銘柄が最後に更新された EasyLanguage 時刻を表す数式を返すクオートフィールド
レートが更新されているかどうかをチェックするのに使えそうです。
1 |
ComputerDateTime |
現在のコンピューター時間の倍精度 10 進 DateTime 値を返します。
例
Value1 = ComputerDateTime(); は、現在のコンピューターの日時を DateTime 形式で返します。
1 |
LastCalcTime |
最後に完了したバーの時刻を 24 時間形式 (HHMM) で返します。
たとえば、この関数が 1700 を返す場合、最後のバーが午後 5 時に完了、つまり引けたことを意味します。
ふ~ん。
インプットパラメータ
TradeStationのチャート上にインジケーターを挿入して、インジケーター上で右クリックすると、インジケーターの設定メニューが表示されます。
「一般」のとなりの「入力」タブを押すと、インプットパラメータの項目が表示されます。
これがMQLで言うところのextern,inputパラメータです。
(ターミナル上から編集できる変数です)
これがソースコード上のinputと対応しています。
1 2 3 4 5 6 7 |
inputs: Price( Close ) [DisplayName = "Price", ToolTip = "Enter an EasyLanguage expression to use in the moving average calculation."], Length( 9 ) [DisplayName = "Length", ToolTip = "Enter number of bars over which to calculate the simple moving average."], Displace( 0 ) [DisplayName = "Displace", ToolTip = "Displacement. Enter the number of bars by which plots will be displaced. Displacement may be positive (left) or negative (right)."] ; |
オーダーの文法と使い方
EasyLanguageにはオーダーが4種類あります。
オーダーの種類
Buy
新規買い。ポジションを保持していない場合、新規で買いポジションを建
てます。売りポジションを保持している場合、ドテンして買いポジションを建て
ます。
SellShort
新規売り。ポジションを保持していない場合、新規で売りポジショ
ンを建てます。買いポジションを保持している場合、ドテンして売りポジション
を建てます。
Sell
売却。買いポジションを決済します。
BuyToCover
買戻し。売りポジションを決済します
株の場合、デフォルトが現物なので、ちょっと癖がありますね。
基本はBuyとSellの組み合わせで良いんじゃないでしょうか。
利用者の口座が信用取引に対応しているかは分からないので、
売りから入るとエラーになったりバグが発生すると思います。
オーダーのタイミング
オーダーのタイミングは、
1 2 3 4 5 |
... this bar on close; ... next bar at open; ... next bar at market; ... next bar at yourprice Stop; ... next bar at yourprice Limit; |
があります。
基本、即座に成行でエントリーはできないようで、
次の足の始値エントリーになります。
とりあえず指値逆指値をプログラムからできるので、”見せ板”のイタズラは実装できるってことです。
それで良しとしましょう。
株の場合、日足で利用していると窓が開いてとんでもない値で約定してしまうリスクがあるので、
シグナルがあらかじめ分かるタイプの場合、先に指値か逆指値を入れておいた方が良いような気がします。
てか、This bar on closeってリアルタイムトレードで使えないなら、
バックテストで使う意味がないように思うのですが…
バックテストで検証だけして、実際のリアルトレードは裁量でやれってことでしょうか。意味不明です。
注文方法
注文方法は、
1 2 3 4 |
(buy,sell) next bar at market; (buy,sell) next bar at 指値価格 limit; (buy,sell) next bar at 逆指値価格 stop; (buy,sell) this bar on close; |
という感じです。
1 |
Buy ("MyFirstEntry") next bar at open; |
のようにそれぞれのオーダーに名前を付けることもできます。
一つのストラテジー内でマルチロジックをする場合に使えます。
取引量は、ストラテジー内で注文数量を設定しない場合、デフォルトで 100 株になります。
取引銘柄の単元が 100 株でない銘柄の場合は、バグるので別途変更する必要があります。
数量変更は、
1 |
Buy ("My Entry") 100 shares next bar at open; |
のように、数量 sharesを付け足します。
ポジション関数
ポジションを決済するにはポジションに関する処理を行う必要があります。
保有しているポジションの処理をする関数を見ていきます。
1 |
GetPositionSymbol(strAccountNumber, iPositionId) |
アルファベット順にソートされた口座ポジションのリストにおけるポジション位置番号に関連付けられた銘柄を特定します。
この関数を GetNumPositions とともに使用すれば、使用可能なポジションを列挙できます。
※ポジションを追加または削除すると、ソートされたポジションリストが変更されるため、既存のポジションのインデックス値が変更されることがあります。
(これは仕方ないですね。というよりこの方法ではない場合、番号がずっと保持されるので、その処理に困ります。)
1 |
GetNumPositions(strAccountNumber) |
特定の口座の未決済ポジションの数を返します。無効な口座に対しては、または建玉なしの場合は、ゼロを返します。
つまり、PositionsTotal()と同じです。
1 |
GetAccountID(); |
チャート上のストラテジーや分析テクニックに関連する口座の文字列表示を返します。
上のGetNumPositions内の引数に使えます。
1 |
OpenPositionProfit |
現在の未決済ポジションの現在の損益を返します。
1 |
GetPositionOpenPL(strSymbol, strAccountNumber) |
ポジションの未実現損益を識別する浮動小数点値を返します。
ポジションが存在しない場合、または銘柄や口座が無効である場合は、ゼロを返します。
1 |
PositionProfit(Num); |
指定されたポジションの現在の利益または損失を返します。
Num は、過去のポジション数 (最大 10) を表す数式です。
1 |
GetSymbolName |
テクニックが適用される銘柄の名前を返します。要するにSymbol()です。
1 |
MarketPosition(Num) |
指定したポジションについて、ショートポジションまたはロングポジションの数値を返します。
•ショートポジションの場合は -1 が返され、ロングポジションの場合は 1 が返されます。
1 |
POSITIONID |
オプションステーションの予約語で、識別可能なポジションの値を返します。
POSITIONID の戻り値:
ロングコール = 1
ロングプット = 2
コール書き込み = 3
プット書き込み = 4
強気/コールデビットスプレッド = 5
弱気/プットデビットスプレッド = 6
強気/プットクレジットスプレッド = 7
弱気/プットクレジットスプレッド = 8
ロングストラドル = 9
ロングストラングル = 10
ショートストラドル = 11
ショートストラングル = 12
ロングコールバタフライ = 13
ロングプットバタフライ = 14
コールタイムスプレッド = 15
プットタイムスプレッド = 16
カバードコール = 17
マリッドプット = 18
コールレシオスプレッド = 19
プットレシオスプレッド = 20
コールレシオスプレッド = 21
プットレシオスプレッド = 22
ロング株式 = 23
ロング先物 = 24
ショート株式 = 25
ショート先物 = 26
シンセティックロング = 27
シンセティックショート = 28
コールアイアンバタフライ = 29
プットアイアンバタフライ = 30
ロングアイアンバタフライ = 31
ショートアイアンバタフライ = 32
ショートコールコンドル = 33
ショートプットコンドル = 34
ロングコールコンドル = 35
ロングプットコンドル = 36
ショートコールバタフライ = 37
ショートプットバタフライ = 38
プットヘッジ = 39
合成プット = 40
または識別不能
メソッド 宣言と使い方
EasyLanguageでは、一応メソッドが使えます。
メソッドとは、かんたんに言うと関数みたいなものです。
(厳密には微妙に違う)
メソッドに関しては特にクセはなく、
1 2 3 4 |
method 型 メソッド名(型 引数) 処理; return 返り値 end; |
で行けます。
ローカルで宣言した場合、使える範囲もローカルです。
1 2 3 4 5 6 |
method double myMethod(int Param1) var: double myVar; begin {EasyLanguage statements} return myVar end; |
ヘルプを読むと、
メソッド内でのみ使用されるローカル変数は、メソッド宣言ステートメントおよびそのメソッドの本文を含む begin…end ステートメントの後に宣言します。
と書いてありますが、”ステートメントの前”の間違いだと思います。
(サンプルでは思いっきり前になっていますからね。)
直観で行くと、begin以降に変数を宣言したくなるので、
ここはやや直観に反する書き方です。
ファイル関数
TradeStationにもファイル関数は一応ありますが、
あまり使い勝手は良くないみたいです。
1 |
File("c:\windows\filename.txt") |
Print ステートメントから指定したファイルに情報を送信できます。
1 |
Print(File("c:\data\mydata.txt"), Date, Time, Close); |
これができれば外部ソフトとの連携が可能になります。
ファイルの内容を追加して、上書きする場合は、
1 |
FileAppend("str_Filename", "str_Text") ; |
が使えます。
ユーザーによって指定された既存の ASCII ファイルに情報を送信し、その情報をファイルの最下部に追加します。
ファイルがない場合は、作成されます。
ファイルに数式を送信するには、まず、NumToStr 関数を使用して文字列式に変換する必要があります。
ただ、大きな問題があります。
それは!!!受信ができない!!!
送信しかできません。
そのため、ファイル関数を使って株データをMetaTraderに送ることはできても、
TradeStationがデータを受け取ることはできません。
利用範囲が限られてしまいますね。
データを受け取ることができれば、コピーツールや外部のトレードデータを使ったロジックなどもできたのですが、
今後のバージョンアップに期待しましょう。
関連記事
-
株の自動売買プログラムを開発する6つのやり方
FX業界ではMT4/MT5のおかげもあり、個人レベルでも自動売買やシステムトレードが盛んにおこなわれ
-
トレードステーションの使い方(初心者)
トレードステーションのチャートの表示方法 TradeStation/トレードステーションは、Met
-
[EasyLanguage]パーフェクトオーダーを作る(トレードステーション)
今回は久々にプログラミングを触ります。 TradeStationはデフォルトで比較的なインジケータ
-
日本株の個別銘柄でシステムトレード検証&自動売買(ダウンロードあり)
MT4/MT5というとFXでのトレードプラットフォームの印象が強いですが、株のトレードも可能です。特
-
[EasyLanguage]ストラテジーのコードを読み解く(トレードステーション)
移動平均線のクロスのストラテジーのプログラミングを見ていきたいと思います。 思っていたより短い
コメント
トレードステーションのインディケーターをメタトレーダー4のインディケーターに作り直す事はできますでしょうか?
ファイルをご覧になって頂き、もし可能であれば
お見積りをお願いしたいのでメールアドレスのほうに
ご連絡頂ければ幸いです。
宜しくお願い致します。