Indikator lebih mudah dikembangkan jika kamu memahami cara nilainya dihasilkan. Apa yang masuk dalam perhitungan? Apa yang disimpan untuk candle berikutnya? Apa yang berubah jika rata-rata atau sumber harganya diganti? Sumber kode bisa menjawab pertanyaan tersebut.

Pustaka ta PyneCore ditulis dalam Pyne code. Variabel Persistent, pemanggilan fungsi, dan kondisi di dalamnya menggunakan perilaku yang sudah dipelajari dalam buku. Seluruh sumber tersedia, sehingga kamu bisa menelusuri indikator siap pakai seperti program sendiri.

Ini adalah bab lanjutan tentang membaca sumber dan melakukan percobaan. Kamu tidak perlu memahami seluruh pustaka sekaligus. Mulai dari fungsi pendek, lalu ikuti pemanggilan yang mendasarinya.

Membuka implementasi sebenarnya

  1. Buka file moving_averages.py yang sudah dibuat di PyneIDE.
  2. Pada baris ta.ema(close, 10), tahan Command pada macOS atau Ctrl pada Windows maupun Linux, lalu klik nama ema. Kamu juga bisa menggunakan Go to Definition pada menu klik kanan.
  3. Editor membuka file ta.py dari PyneCore yang terpasang, pada definisi ema.
  4. Baca deskripsi fungsi, lalu isinya. Jika fungsi memanggil fungsi lain, kamu juga bisa menuju definisi fungsi tersebut.
Editor PyneIDE menampilkan definisi ema dalam file pustaka ta.py beserta deskripsi nilai awalnya.
Menuju definisi membuka fungsi EMA dalam file ta.py yang terpasang. Program sendiri tetap berada pada tab terpisah.

Kamu sudah mencoba melihat parameter dan menuju definisi dalam bab Bantuan saat menulis kode. Tindakan yang sama membuka sumber RSI, MACD, dan fungsi lainnya. Referensi lengkap ta membantu mencari fungsi dan memahami parameternya.

SMA: penjumlahan di balik rumus

Dua baris perhitungan ta.sma:

length = int(length)
return lib_math.sum(source, length) / length

Rata-rata adalah jumlah nilai dalam jendela dibagi jumlah elemennya. Setelah panjang diubah menjadi bilangan bulat, lib_math.sum melakukan penjumlahan. Statusnya tidak berada dalam isi sma: perhitungan penjumlahan yang dipanggil menanganinya. Jika pemanggilan ditelusuri lebih jauh, modul math.py membawamu ke implementasi _math_stateful.py.

Ini kebiasaan membaca yang perlu diingat: fungsi pendek pun bisa menggunakan status. Perilaku fungsi yang dipanggil juga merupakan bagian perhitungannya. Moving average yang ditulis sendiri menjumlahkan nilai jendela yang sama dengan perulangan buatan.

EMA dan RMA: memperbarui rata-rata tersimpan

Setelah pemanasan, EMA melakukan langkah ini:

last_val = last_val + alpha * (source - last_val)
return last_val

last_val adalah rata-rata sebelumnya dan source adalah nilai saat ini. Kita memperbarui rata-rata lama dengan sebagian selisih keduanya. Pada EMA, alpha bernilai 2 / (length + 1). Dengan panjang sepuluh, sekitar 18,18 persen selisih harga baru dan rata-rata lama ditambahkan ke rata-rata lama.

Dalam sumber, alpha dan last_val adalah variabel Persistent. last_val awalnya tidak tersedia, sehingga fungsi mencoba mengisinya terlebih dahulu dengan SMA sepanjang yang sama:

if not (last_val == last_val):
    last_val = sma(source, length)
    return last_val

Selama data untuk SMA belum cukup, hasil tetap tidak tersedia. Setelah rata-rata awal terbentuk, nilai sebelumnya diperbarui. not (last_val == last_val) memeriksa nilai yang tidak tersedia: nilai tersebut tidak sama dengan dirinya sendiri. Dalam contoh sendiri, kamu menggunakan na(value) untuk tujuan yang sama.

RMA, atau penghalusan Wilder, dimulai dengan cara serupa tetapi diperbarui secara berbeda:

last_val = (last_val * (length - 1) + source) / length
return last_val

Dengan panjang sepuluh, bobot nilai baru adalah sepersepuluh. Untuk panjang yang sama, EMA memberi bobot lebih besar pada nilai baru. Karena itu, kedua penghalusan merespons rangkaian harga yang sama secara berbeda.

Sumber lengkap juga memperlihatkan penanganan input yang tidak tersedia dan jalan pintas untuk panjang satu. Dua varian sendiri dengan rumus sama pun bisa menghasilkan nilai berbeda jika nilai awal, penanganan nilai hilang, atau candle tempat pemanggilannya berbeda. Urutan operasi floating point juga berpengaruh; pertahankan urutannya untuk perbandingan yang tepat.

RSI: dua perubahan yang dihaluskan terpisah

RSI menangani kenaikan dan penurunan sumber secara terpisah. Dalam PyneCore, baris perhitungan utamanya:

rma_u = rma(builtins.max(source - prev_src, 0.0), length)
rma_d = rma(builtins.max(prev_src - source, 0.0), length)
prev_src = source

prev_src adalah nilai sumber valid sebelumnya yang disimpan oleh variabel Persistent. Jika harga naik dari 100 ke 103, perubahan naik adalah 3 dan perubahan turun 0. Jika turun dari 103 ke 101, keduanya menjadi 0 dan 2. RMA menghaluskan kedua deret secara terpisah; kedua lokasi pemanggilan memiliki status sendiri.

prev_src diperbarui setelah kedua selisih dihitung. Urutan ini sama seperti dalam latihan tambahan nilai sebelumnya yang persisten.

RSI dibuat dari rasio kedua perubahan yang dihaluskan:

if rma_d <= 1e-10:
    return 100.0
if rma_u <= 1e-10:
    return 0.0

return 100 - 100 / (1 + rma_u / rma_d)

Tanpa pergerakan turun, hasilnya 100; tanpa pergerakan naik, hasilnya 0. Sumber juga menangani nilai yang sangat kecil dan memeriksa sisi turun terlebih dahulu: jika kedua sisi berada di bawah batas, hasilnya 100. Detail ini tidak terlihat dari rumus saja.

Harga valid pertama belum menghasilkan perubahan. RSI menyimpannya terlebih dahulu dan baru bisa memulai kedua penghalusan dengan nilai berikutnya. Jumlah perubahan menentukan pemanasan indikator. RSI tidak menunjukkan probabilitas: nilai 70 tidak berarti peluang harga naik sebesar 70 persen.

MACD: indikator baru dari moving average

MACD menghitung selisih dua EMA, lalu membuat EMA dari selisih tersebut. Langkah utama tanpa pemeriksaan nilai yang tidak tersedia:

fast = ema(source, fastlen)
slow = ema(source, slowlen)
macd_val = fast - slow
signal = ema(macd_val, siglen)

Tiga nilai yang dikembalikan:

return macd_val, signal, macd_val - signal

Garis MACD adalah selisih rata-rata cepat dan lambat. Garis sinyal adalah versi yang dihaluskan dari selisih itu. Histogram adalah selisih kedua garis, sehingga bernilai nol ketika kedua garis sama.

Satu pemanggilan menghasilkan tiga nilai yang bisa diterima oleh tiga variabel:

macd_line, signal_line, histogram = ta.macd(close, 12, 26, 9)

Urutannya penting: garis MACD, garis sinyal, histogram. Selama kedua rata-rata harga belum tersedia, selisih juga belum tersedia. Setelah itu, garis sinyal masih memiliki pemanasan sendiri. Dengan demikian, nilai awal yang tidak tersedia pada indikator gabungan juga berasal dari perhitungan internalnya.

ATR: celah harga juga termasuk rentang

Implementasi ATR singkat:

return rma(tr(True), length)

Kamu sudah mengenal RMA; di sini RMA menghaluskan True Range, atau rentang sebenarnya. Nilainya adalah maksimum dari tiga jarak berikut:

  • selisih harga tertinggi dan terendah saat ini;
  • jarak harga tertinggi saat ini dari harga penutupan candle sebelumnya;
  • jarak harga terendah saat ini dari harga penutupan candle sebelumnya.

Jika harga penutupan sebelumnya 100, harga terendah saat ini 108, dan harga tertinggi 110, rentang candle sendiri hanya 2. Namun, true range adalah max(2, 10, 8), yaitu 10: perhitungan juga mencakup lompatan harga sejak penutupan sebelumnya.

Pada candle pertama, ketika harga penutupan sebelumnya belum tersedia, tr(True) menggunakan high - low. Dalam sumber, harga penutupan sebelumnya dibaca dari data internal yang disediakan runtime. ATR menunjukkan besarnya pergerakan dalam satuan harga, bukan arahnya.

Bollinger Band: rata-rata dan simpangan baku

Garis tengah ta.bb adalah SMA; kedua batas berbeda dari garis tengah sebesar kelipatan simpangan baku yang ditentukan. Sumber menghitung simpangan baku dan rata-rata terlebih dahulu:

std_dev = stdev(series, length)
middle = sma(series, length)

Nilai yang dikembalikan untuk titik tengah valid:

std_dev *= mult
return middle, middle + std_dev, middle - std_dev

Simpangan baku menjelaskan seberapa tersebar nilai dalam jendela di sekitar rata-rata. Jika titik tengah 100, simpangan baku 3, dan pengali 2, batas atas adalah 106 dan batas bawah 94. Pemanggilan ini juga menghasilkan tiga nilai, tetapi urutannya berbeda dari MACD: tengah, batas atas, batas bawah.

Versi sendiri: tiru hasil asli terlebih dahulu

Buat file bands_workshop.py. Fungsi buatan kita menyusun band dari bagian pustaka yang lebih sederhana. Kita juga menghitung batas atas ta.bb siap pakai sebagai dasar perbandingan.

"""
@pyne edge
"""
from pynecore.lib import close, color, input, plot, script, ta


def custom_bands(source: float, length: int, multiplier: float) -> tuple[float, float, float]:
    middle = ta.sma(source, length)
    deviation = ta.stdev(source, length)
    upper = middle + multiplier * deviation
    lower = middle - multiplier * deviation
    return middle, upper, lower


@script.indicator("Bands Workshop", overlay=True)
def main(
    length: int = input.int(20, title="Length", minval=2, maxval=200),
    multiplier: float = input.float(2.0, title="Deviation multiplier", minval=0.1, maxval=5.0),
):
    builtin_middle, builtin_upper, builtin_lower = ta.bb(close, length, multiplier)
    own_middle, own_upper, own_lower = custom_bands(close, length, multiplier)
    plot(builtin_upper, "Built-in upper", color=color.blue, linewidth=3)
    plot(own_upper, "Custom upper", color=color.orange)
    plot(own_middle, "Custom middle", color=color.green)
    plot(own_lower, "Custom lower", color=color.gray)

tuple[float, float, float] menandakan tipe hasil yang terdiri dari tiga angka. Baris return middle, upper, lower mengembalikan ketiganya, dan tiga nama variabel sebelum pemanggilan menerima nilai masing-masing. builtin_middle dan builtin_lower belum digambar, tetapi kamu juga bisa menggunakannya untuk pemeriksaan nanti.

Jalankan pada data demo. Batas atas buatan dan siap pakai saling bertumpuk; garis oranye tipis mengikuti garis biru yang lebih tebal. Arahkan penunjuk mouse ke satu candle dan bandingkan nilai Built-in upper dengan Custom upper. Dengan panjang dua puluh, sembilan belas candle pertama belum memiliki jendela lengkap.

Grafik di samping fungsi buatan bands_workshop.py memperlihatkan nilai Built-in upper dan Custom upper yang sama; garis tengah dan batas bawah buatan juga terlihat.
Nilai batas atas siap pakai dan buatan pada candle pilihan sama-sama 216,85 (ditampilkan sebagai 216.85 dalam antarmuka Inggris). Kedua garis bertumpuk.

Untuk pemeriksaan lebih teliti, buka nilai yang diekspor melalui Open plot output CSV pada bilah alat grafik. Saat membuat varian sendiri, periksa titik valid pertama dan nilai setelahnya. Garis yang tampak sama pun bisa memiliki selisih kecil.

Coba sendiri: garis tengah EMA

Ubah hanya garis tengah custom_bands: gunakan EMA sebagai pengganti SMA. Pertahankan perhitungan simpangan baku dan pemanggilan ta.bb siap pakai untuk perbandingan.

Sebelum menjalankannya, perkirakan: apakah batas atas buatan akan selalu bertumpuk dengan batas siap pakai? Apa yang terjadi setelah perubahan harga mendadak?

Solusi latihan

Baris perhitungan pertama dalam fungsi buatan:

middle = ta.ema(source, length)

Kedua batas diukur dari EMA ini, sedangkan perhitungan ta.stdev tetap sama. Garis tengah buatan dan kedua batas umumnya bergeser dari band asli. Selisih kedua nilai atas sama dengan selisih EMA dan SMA karena simpangan baku dan pengali yang sama ditambahkan pada keduanya.

Ini sudah menjadi varian percobaanmu sendiri. Garis yang berbeda saja tidak menunjukkan apakah aturan trading akan menghasilkan hasil lebih baik dengannya; kamu bisa memeriksanya dalam strategi terpisah dengan data dan pengaturan yang sama.

Melanjutkan penelusuran pustaka

Pilih satu indikator dan jelaskan dengan kata-katamu sendiri data yang diterima, hal yang disimpan, dan hasil yang diberikan. Ikuti pemanggilan internal sampai perhitungannya jelas. Pada RSI, misalnya, jalur rsi → rma → sma membawamu dari selisih menuju penghalusan dan nilai awal.

Baca juga cabang yang menangani nilai tidak tersedia, pemanasan, dan kasus batas. Jika membuat varian sendiri, ubah satu detail terlebih dahulu, lalu bandingkan hasilnya dengan versi asli. Dengan begitu, kamu bisa membedakan perubahan yang disengaja dari kesalahan perhitungan.

Sumber fungsi pustaka lainnya bisa dibuka dengan klik sambil menahan Command atau Ctrl yang sama. Indikator panjang mungkin memerlukan lebih banyak waktu, tetapi cara membacanya tetap sama: input, data yang disimpan, perhitungan, hasil.