Lewati ke isi

C# untuk trading algoritmik

Apa itu C#

C# adalah bahasa pemrograman berorientasi objek yang digunakan untuk membangun berbagai layanan dan aplikasi. Sintaksnya yang jelas dan terstruktur membuatnya mudah dipelajari dan dibaca, bahkan oleh pemula, sambil menyediakan pendekatan terstruktur untuk menulis kode yang ringkas dan dapat digunakan kembali.

Algoritma C# dalam satu menit!

  • Bahkan jika Anda belum pernah bekerja dengan C# sebelumnya, membuat dan menerapkan bot pertama Anda atau indikator hanya membutuhkan waktu beberapa menit.
  • Karena C# mudah digunakan, Anda dapat dengan cepat menulis ulang cuplikan kode apa pun dari dokumentasi ini untuk memenuhi kebutuhan Anda.
  • Saat menggunakan C#, Anda dapat mengakses sejumlah besar pustaka yang berisi kelas dan metode yang telah ditentukan sebelumnya. Metode-metode ini dapat menangani tugas-tugas umum secara efisien, memberi Anda kebebasan untuk menyelesaikan masalah trading yang kompleks.
  • Dalam C#, Anda dapat menulis kode yang tidak memblokir thread server saat dieksekusi. Dengan kata lain, Anda dapat memulai tugas-tugas tertentu secara bersamaan dengan tugas-tugas lainnya.

Apa itu .NET?

Agar program C# dapat berjalan, kode sumbernya harus dikompilasi menjadi Intermediate Language (IL). Kode IL ini mengikuti spesifikasi Common Language Infrastructure (CLI) dan kemudian dikompilasi menjadi instruksi mesin native saat runtime. Framework .NET menyediakan lingkungan eksekusi virtual yang dibangun di atas pustaka kelas yang luas dan Common Language Runtime (CLR), implementasi CLI dari Microsoft.

Tanpa masuk ke kerumitan teknis, .NET memenuhi fungsi-fungsi berikut:

  • Memfasilitasi pengembangan dan eksekusi aplikasi: .NET SDK sudah berisi beberapa kompiler dan mesin build bawaan, menghilangkan kebutuhan untuk membuat solusi kustom apa pun.
  • Menyediakan pustaka runtime: Saat menambahkan tipe data atau koleksi baru ke kode Anda, Anda akan sering menemukan bahwa .NET sudah menawarkan kelas dan metode yang sesuai untuk tugas tersebut.

Dasar-dasar C#

Tipe data dan deklarasi variabel

Tipe data adalah cara mengkategorikan data sehingga C# tahu persis bagaimana memperlakukan variabel dan properti. Dalam deklarasi variabel/properti, tipe data selalu mendahului nama variabel/properti.

1
string developer = "I am developing cBots, plugins, and indicators!";

Sebagai alternatif, Anda dapat menggunakan kata kunci var untuk menghindari menentukan tipe data.

1
var developer = "I am developing cBots, plugins, and indicators!";

Objek dan kelas

Anggap objek sebagai abstraksi dari entitas berwujud atau tidak berwujud. Entitas-entitas ini dapat memiliki karakteristik tertentu (properti) dan dapat melakukan berbagai operasi (metode). Sebaliknya, kelas berfungsi sebagai template untuk pembuatan objek.

Karena C# adalah bahasa berorientasi objek, kelas juga dapat mewarisi properti dan metode dari kelas lain. Perhatikan contoh berikut di mana kita mendeklarasikan kelas NewBot baru yang mewarisi dari kelas Robot. Kita juga mendefinisikan beberapa properti kelas baru.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* We use the colon sign to designate inheritance.
Additionally, we used expressions in square brackets to
specify the parameters that apply to the entire class */
[Robot(AccessRights = AccessRights.None)]
public class NewBot : Robot
{
    /* We declare a custom class property and make it
    read-only. */
    public string CustomProperty { get; }

    /* In this declaration, we define the default value of a
    custom parameter. */
    [Parameter("BotName", DefaultValue = "Traders First!")]

    /* We declare the BotName property which is changeable via
    the "BotName" parameter. */
    public string BotName { get; }

    /* We also declare the BotComment parameter.
    It can be both read and set. */
    [Parameter("BotComment", DefaultValue = "Our super-duper bot!")]
    public string BotComment { get; set; }
}

Tipe data

Karena C# adalah bahasa yang strongly-typed, perlu menentukan tipe data saat mendeklarasikan variabel dan properti kelas. Singkatnya, tipe data merupakan kelas unik dengan set perilaku yang berbeda. Perhatikan contoh berikut di mana berbagai tipe data ditentukan untuk properti kelas dan parameter terkait yang berbeda.

1
2
[Parameter("Price")]
public DataSeries Source { get; }

Dalam kode di atas, tipe data DataSeries mewakili daftar nilai yang hanya dapat dibaca dan oleh karena itu biasanya digunakan untuk mewakili harga pasar.

Ketika ada kebutuhan untuk membuat parameter multi-opsi, Anda dapat menggunakan tipe data enum bawaan seperti yang dijelaskan di bawah ini. Anda dapat menganggap enum sebagai kelas khusus yang berisi berbagai konstanta.

1
2
3
4
5
6
7
8
9
public enum Option
{
    First,
    Second,
    Third
}

[Parameter("Option", DefaultValue = Option.Third)]
public Option SelectedOption { get; set; }

Untuk mengakses konstanta yang terdapat dalam enum, gunakan sintaks berikut.

1
var newOption = Option.First;

Jika parameter atau properti perlu berupa angka, Anda paling sering akan menggunakan tipe data int (integer) atau double (desimal). Meskipun tipe double memiliki presisi yang lebih rendah daripada tipe decimal, tipe ini juga kurang memakan sumber daya.

1
2
[Parameter("MA Periods", DefaultValue = 14, MinValue = 1, MaxValue = 20)]
public int Periods { get; set; }

Terakhir, tipe bool biasanya mewakili input ya atau tidak. Nilai ya dan tidak berkorespondensi dengan true dan false, masing-masing.

1
2
[Parameter("Message", DefaultValue = true)]
public bool DisplayChartMessage { get; set; }

Namespace

Namespace bertindak sebagai kumpulan kelas yang ditentukan. Setelah Anda menetapkan kelas ke namespace, kelas tersebut dapat diakses kemudian dengan menggunakan notasi Namespace.ClassName. Kita akan menetapkan NewBot kita ke namespace CoolTradingBots.

1
2
3
4
5
6
7
8
namespace CoolTradingBots
{
    [Robot(AccessRights = AccessRights.None)]
    public class NewBot : Robot
    {
        // ...
    }
}

Metode kelas

Metode kelas didefinisikan setelah deklarasi kelas. Semua objek dari kelas NewBot kita akan dapat memanggil metode CustomTradeOperation(). Metode ini mengambil dua argumen, yaitu objek Symbol dan objek double. Metode kita seharusnya mengambil simbol dan mengeksekusi semacam tindakan trading untuk volume yang ditentukan

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
namespace CoolTradingBots
{
    [Robot(AccessRights = AccessRights.None)]
    public class NewBot : Robot
    {
        // ... Defining the class parameters.

        // We declare the CustomTradeOperation method. 
        protected override void CustomTradeOperation(string symbolName, double volume)

        {
            // This space is for declaring the method logic. 
        }
    }
}

Pustaka kelas

Pustaka kelas (dan selanjutnya, metode kelas) dapat diakses melalui namespace mereka seperti yang ditunjukkan dalam contoh di bawah ini.

1
CoolTradingBots.NewBot.CustomTradeOperation(symbolName, 10000)

Sebagai alternatif, Anda dapat mengetikkan kata kunci using di awal kode Anda untuk menentukan namespace tertentu dan menghindari redundansi. Perhatikan cuplikan kode berikut.

1
2
3
using CoolTradingBots;

NewBot.CustomTradeOperation(symbolName, 10000)

Pernyataan kondisional

Untuk menggunakan pernyataan kondisional, gunakan kata kunci yang diikuti oleh ekspresi dalam tanda kurung. Contoh di bawah ini menggunakan kata kunci if untuk menyelesaikan metode CustomTradingOperation() kita. Untuk melakukannya, kita menggunakan metode EvaluateMarket() yang didefinisikan dalam namespace Analytics.Actions.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
namespace CoolTradingBots
{
    [Robot(AccessRights = AccessRights.None)]
    public class NewBot : Robot
    {
        // ... Defining the class parameters.

        protected override void CustomTradeOperation(string symbolName, double volume)
        {
            // We declare and initialize the 'result' variable.
            var result = Analytics.Action.EvaluateMarket();

            // We use a conditional statement based on the IsSuccessful property.
            if (result.IsSuccessful)
            {
                Print("Operation successful!")
            }
        }
    }
}

Koleksi

Koleksi didefinisikan sebagai wadah yang dapat menyimpan satu atau lebih objek dari kelas tertentu.

Koleksi dapat diindeks sepenuhnya, artinya anggotanya dapat diakses dengan melewatkan nilai integer tertentu dalam tanda kurung siku. Perhatikan contoh berikut di mana metode Calculate() mencetak properti bar yang diakses melalui indeksnya.

1
2
3
4
5
public override void Calculate(int index)
{
       var bar = Bars[index];
       Print($"{bar.Open} | {bar.High} | {bar.Low} | {bar.Close}");
}

Buat ekstensi cTrader

Dalam cuplikan di bawah ini, kita membuat bot trading dasar hanya menggunakan pengetahuan yang dibahas di bagian-bagian sebelumnya.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System; 

namespace Spotware.cBots
{
    [Robot(AccessRights = AccessRights.None)]
    public class SuperAwesomeBot : Robot
    {

        /* In the below method, we define the operation(s) that our bot should
        perform when it is launched. */
        protected override void OnStart()
        {
            var result = ExecuteMarketOrder(TradeType.Buy, symbolName, 10000);

            /* We use a conditional statement using the IsSuccessful property of the
            TradeResult object. */
            if (result.IsSuccessful)
            {
                var position = result.Position;
                Print ("Position entry price is {0}", position.EntryPrice);
            } 
        }
    }
}

Operasi sinkron dan asinkron

Seperti yang dinyatakan sebelumnya, C# sepenuhnya mendukung operasi asinkron. Diagram di bawah ini menjelaskan contoh dasar bagaimana aktivitas trading dilakukan dalam eksekusi sinkron.

graph TD
    A(Menemui Sinyal Teknis) ==> B(Eksekusi Order Market)
    B ==> C(Take Profit/Stop Loss <br>Tercapai)
    C ==> D(Tutup Posisi)
    D ==> A

Eksekusi sinkron memiliki satu kelemahan penting. Dalam contoh di atas, tindakan mengeksekusi order pasar sepenuhnya menempati semua thread server, yang berarti robot trading Anda tidak dapat melakukan hal lain sebelum operasi ini selesai.

Ini kurang ideal ketika Anda ingin bereaksi cepat terhadap peristiwa pasar dan volatilitas. Idealnya, bot Anda harus dapat menyimpan berbagai tindakan atau menunda tugas-tugas tertentu untuk terlibat dalam aktivitas lain yang lebih mendesak. Kita akan memperluas contoh kita untuk lebih mencerminkan bagaimana operasi asinkron dilakukan.

graph TD
    A([Menemui Sinyal Teknis]) ==> B([Menempatkan Order Beli]) & C([Menempatkan Order Jual<br> untuk Hedging]) ==> D([Sebuah Order Mencapai <br>Take Profit/Stop Loss-nya])
    D ==> E([Menutup Posisi])
    E ==> A

Dalam contoh di atas, robot trading kita secara bersamaan menempatkan order di kedua arah untuk melakukan hedging posisinya. Berbeda dengan operasi sinkron, tidak perlu menunggu satu operasi selesai sebelum melanjutkan ke operasi lainnya. Hal ini secara signifikan memperluas peluang pengembang untuk membuat robot trading yang efisien dan andal.

Perhatikan bahwa eksekusi asinkron berbeda dari multi-threading:

  • Dalam eksekusi asinkron, semua tugas dimulai pada thread yang sama. Ketika tugas-tugas tersebut disimpan atau ditunda, mereka membebaskan thread ini dan, ketika eksekusinya dilanjutkan nanti, itu terjadi pada thread berbeda yang dipilih dari kumpulan thread.
  • Ketika multi-threading, semua tugas dimulai pada thread yang berbeda dan melanjutkan eksekusinya pada thread awal mereka. Tidak ada pengacakan thread.

cTrader tidak pernah memanggil metode Anda secara paralel sehingga Anda tidak perlu khawatir tentang masalah multi-threading.

Image title