C#とは?
C#はオブジェクト指向プログラミング言語で、様々な種類の拡張機能やアプリケーションを構築することができます。オブジェクト指向言語であるC#は、プログラミングの経験がなくても簡単に習得でき、読むことができます。また、コンパクトで再利用可能なコードを書くための構造化された手段を提供します。
C#がcBotとインジケーターに最適な言語である理由は、以下のとおりです。
- 学習の容易さ:C#を扱ったことがなくても、最初のボットやインジケーターの作成とデプロイには数分しかかかりません。
- 言語の効率性:C#は使いやすいので、このドキュメントにあるコードを必要に応じてすぐに書き換えることができます。
- 豊富なクラスライブラリ:C#と.NETを使用すると、定義済みのクラスとメソッドを含む多数のライブラリにアクセスできます。これらのメソッドは、一般的なタスクを効率的に処理することができ、複雑な取引の問題を解決するために役立ちます。
- 非同期操作のサポート:C#では、実行時にサーバーのスレッドをブロックしないコードを書くことができます。つまり、特定のタスクを他のタスクと同時に開始することができます。
C#のソースコードを実行するには、中間言語(IL)にコンパイルする必要があります。
ILコードは、国際的な共通言語基盤(CLI)仕様に準拠するために必要です。実行中、ILコードはネイティブのマシン命令セットにコンパイルされます。
.NETとは?
.NETは、多くのクラス・ライブラリと共通言語ランタイム(マイクロソフトのCLI解釈)に基づく仮想実行システムです。.NETは次のような機能を果たします。
- アプリケーションの開発と実行を容易に:.NET SDKにはいくつかの組み込みコンパイラとビルドエンジンが含まれているため、カスタムソリューションを作成する必要がありません。
- ランタイムライブラリの提供:コードに特定のデータ型やコレクションを追加したい場合、.NETには対応するクラスとメソッドのセットがすでに用意されている可能性が高いです。
すなわち、.NETは、取引ロボットとインジケーターを作成し実行するための環境です。
C#の基礎
データ型と変数宣言
データ型は、C#が変数やプロパティの扱い方を正確に把握できるように、データを分類するための手段です。変数やプロパティの宣言では、データ型は常に変数名やプロパティ名の前に置かれます。
| 1 | string developer = "I am a developing cBots and indicators!"; |
また、varキーワードを使えば、データ型の指定を避けることもできます。
| 1 | var developer = "I am a developing cBots and indicators!"; |
オブジェクトとクラス
オブジェクトとは、有形または無形の実体を抽象化したものだと考えてください。
これらのエンティティは、特定の特性(プロパティ)を持ち、さまざまな操作(メソッド)を実行できる。また、クラスはオブジェクトを作成するためのテンプレートとして機能します。
C#はオブジェクト指向言語なので、クラスは他のクラスからプロパティやメソッドを継承することもできます。次の例では、Robotクラスを継承した新しいNewBotクラスを宣言しています。また、新しいクラスのプロパティをいくつか定義します。
| 1 | /* We use the colon sign to designate inheritance. |
| 2 | Additionally, we used expressions in square brackets to |
| 3 | specify the parameters that apply to the entire class */ |
| 4 | [Robot(AccessRights = AccessRights.None)] |
| 5 | public class NewBot : Robot |
| 6 | { |
| 7 | /* We declare a custom class property and make it |
| 8 | read-only. */ |
| 9 | public string CustomProperty { get; } |
| 10 | |
| 11 | /* In this declaration, we define the default value of a |
| 12 | custom parameter. */ |
| 13 | [Parameter(“BotName”, DefaultValue = “Traders First!”)] |
| 14 | |
| 15 | /* We declare the BotName property which is changeable via |
| 16 | the “BotName” parameter. */ |
| 17 | public string BotName { get; } |
| 18 | |
| 19 | /* We also declare the BotComment parameter. |
| 20 | It can be both read and set. */ |
| 21 | [Parameter(“BotComment”, DefaultValue = “Our super-duper bot!”)] |
| 22 | public string BotComment { get; set;} |
| 23 | } |
データタイプ(データ型)
C#は強い型付けの言語であるため、変数やクラスのプロパティを宣言する際にデータ型を指定する必要があります。
簡単に説明すると、データ型は異なる動作を持つ固有のクラスを構成します。以下の例では、異なるクラスプロパティと関連するパラメータに様々なデータ型が指定されています。
| 1 | [Parameter(“Price”)] |
| 2 | public DataSeries Source { get; } |
上記のコードでは、DataSeriesデータ型は読み取り専用の値のリストを表し、通常は市場価格を表すために使用されます。
複数のオプションを持つパラメータを作成する必要がある場合は、組み込みのenumデータ型を使用することができます。列挙型は、様々な定数を含む特別なクラスと考えることができます。
| 1 | public enum Option |
| 2 | { |
| 3 | First, |
| 4 | Second, |
| 5 | Third |
| 6 | } |
| 7 | |
| 8 | [Parameter(“Option”, DefaultValue = Option.Third)] |
| 9 | public Option SelectedOption { get; set; } |
列挙型に含まれる定数にアクセスするには、以下の構文を使います。
| 1 | var newOption = Option.First; |
パラメータやプロパティに数値が必要な場合は、int型(整数型)かdouble型(10進数型)を使うことが多いです。
double型は10進数型よりも精度が劣りますが、リソースの消費量も少なくなります。
| 1 | [Parameter(“MA Periods”, DefaultValue = 14, MinValue = 1, MaxValue = 20)] |
| 2 | public int Periods { get; set; } |
最後に、bool型は一般的に「Yes/No」入力を表します。
値’Yes’と’No’は、それぞれ真と偽に対応します。
| 1 | [Parameter(“Message”, DefaultValue = true)] |
| 2 | public bool DisplayChartMessage { get; set; } |
ネームスペース
ネームスペースはクラスの指定されたコレクションとして機能します。一旦クラスを名前空間に割り当てると、後で . 表記を使ってアクセスすることができます。NewBotをCoolTradingBotsネームスペースに割り当てます。
| 1 | namespace CoolTradingBots |
| 2 | { |
| 3 | [Robot(AccessRights = AccessRights.None)] |
| 4 | public class NewBot : Robot |
| 5 | { |
| 6 | // … |
| 7 | } |
| 8 | } |
クラスメソッド
クラスメソッドは、クラス宣言の後に定義されます。NewBot クラスのすべてのオブジェクトは CustomTradeOperation() メソッドを呼び出すことができます。
このメソッドは2つの引数、つまりシンボル・オブジェクトとダブル・オブジェクトを取ります。このメソッドは、シンボルを受け取り、指定された出来高に対して何らかの取引アクションを実行します。
| 1 | namespace CoolTradingBots |
| 2 | { |
| 3 | [Robot(AccessRights = AccessRights.None)] |
| 4 | public class NewBot : Robot |
| 5 | { |
| 6 | // … Defining the class parameters. |
| 7 | |
| 8 | // We declare the CustomTradeOperation method. |
| 9 | protected override void CustomTradeOperation(string symbolName, double volume) |
| 10 | |
| 11 | { |
| 12 | // This space is for declaring the method logic. |
| 13 | } |
| 14 | } |
| 15 | } |
クラスライブラリ
クラス・ライブラリ(およびそれに続くクラス・メソッド)は、以下の例のように名前空間によってアクセスできる。
| 1 | CoolTradingBots.NewBot.CustomTradeOperation(symbolName, 10000) |
あるいは、コードの最初にusingキーワードを入力することで、特定の名前空間(ネームスペース)を指定し、冗長性を避けることもできます。
| 1 2 3 | using CoolTradingBots; NewBot.CustomTradeOperation(symbolName, 10000) |
条件文
条件文を使用するには、キーワードの後に丸括弧で囲んだ式を続けます。以下の例では、if キーワードを使用して CustomTradingOperation() メソッドを確定しています。これを行うには、Analytics.Actions ネームスペースで定義されている EvaluateMarket() メソッドを使用します。
| 1 | namespace CoolTradingBots |
| 2 | { |
| 3 | [Robot(AccessRights = AccessRights.None)] |
| 4 | public class NewBot : Robot |
| 5 | { |
| 6 | // … Defining the class parameters. |
| 7 | |
| 8 | protected override void CustomTradeOperation(string symbolName, double volume) |
| 9 | { |
| 10 | // We declare and initialize the ‘result’ variable. |
| 11 | var result = Analytics.Action.EvaluateMarket(); |
| 12 | |
| 13 | // We use a conditional statement based on the IsSuccessful property. |
| 14 | if (result.IsSuccessful) |
| 15 | { |
| 16 | Print(“Operation successful!”) |
| 17 | } |
| 18 | } |
| 19 | } |
| 20 | } |
コレクション
コレクションは、特定のクラスのオブジェクトを1つ以上格納できる「コンテナ」として定義されます。
コレクションは完全にインデックス可能であり、四角いブレーカーで特定の整数値を渡すことで、そのメンバーにアクセスできることを意味します。
次の例では、Calculate() メソッドが、インデックスを介してアクセスされたバーのプロパティを表示します。
| 1 | public override void Calculate(int index) |
| 2 | { |
| 3 | var bar = Bars[index]; |
| 4 | Print($”{bar.Open} | {bar.High} | {bar.Low} | {bar.Close}”); |
| 5 | } |
cTrader拡張機能の作成
以下のスニペットでは、上記のセクションで説明した知識のみを使用して、非常に基本的なcBotを作成します。
| 1 | using System; |
| 2 | |
| 3 | namespace Spotware.cBots |
| 4 | { |
| 5 | [Robot(AccessRights = AccessRights.None)] |
| 6 | public class SuperAwesomeBot : Robot |
| 7 | { |
| 8 | |
| 9 | /* In the below method, we define the operation(s) that our bot should |
| 10 | perform when it is launched. */ |
| 11 | protected override void OnStart() |
| 12 | { |
| 13 | var result = ExecuteMarketOrder(TradeType.Buy, symbolName, 10000); |
| 14 | |
| 15 | /* We use a conditional statement using the IsSuccessful property of the |
| 16 | TradeResult object. */ |
| 17 | if (result.IsSuccessful) |
| 18 | { |
| 19 | var position = result.Position; |
| 20 | Print (“Position entry price is {0}”, position.EntryPrice); |
| 21 | } |
| 22 | } |
| 23 | } |
| 24 | } |
同期と非同期の操作
前述したように、C#は非同期操作を完全にサポートしています。
以下は同期操作の実行フローです。
- テクニカルシグナルの検知
- 成行注文実行
- TP/SLに掛かる
- ポジションのクローズ
- 「1.」に戻る
同期実行には大きな欠点があります。
成行注文を実行するアクションがすべてのサーバーのスレッドを完全に占有するため、cBotは一連の操作が完了する前に他のことができなくなります。
マーケット・イベントやボラティリティに素早く反応したい場合、これでは理想的ではありません。理想的なのは、cBotが様々なアクションを「保存」したり、特定のタスクを「保留」して他の緊急性の高いアクティビティに従事できることです。
以下は非同期操作の実行フローです。
- テクニカルシグナルの検知
- 「買い」注文実行/「ヘッジ売り」注文実行
- TP/SLに掛かる
- ポジションのクローズ
- 「1.」に戻る
この例では、cBotはポジションをヘッジするために両方向の注文を同時に発注しました。
同期的な操作とは対照的に、1つの操作が完了するのを待ってから別の操作に進む必要はありません。これにより、効率的で信頼性の高いcBotを作成することができるようになります。
なお、非同期実行はマルチスレッドとは異なるものです。
- 非同期実行では、すべてのタスクは同じスレッド上で開始されます。「保存」または 「保留」されると、そのスレッドは解放され、後で実行が続く場合には、スレッドプールから選ばれた別のスレッドで実行されます。
- マルチスレッドの場合、すべてのタスクは異なるスレッドで開始し、最初のスレッドで実行を続けます。スレッドの「シャッフル」はありません。
cTrader Automateはメソッドを並列に呼び出すことはないので、マルチスレッドの問題を心配する必要はありません。
