Meningkatkan Performa Model Prediksi Harga Saham dengan Relative Strength Index (RSI)
PART #01: INTRODUCTION
Project ini masuk dalam kategori time series prediction. Sebelum membahas lebih dalam, mari kita mengenal terlebih dahulu definisi dari stock market. Stock atau yang juga dikenal dengan istilah ekuitas adalah sebuah keamanan yang mewakili kepemilikan dari bagian kecil dari perusahaan. Stock diperjualbelikan di bursa saham dan merupakan dasar dari terciptanya banyak portfolio investor. Perdagangan saham harus mengikuti aturan pemerintah guna melindungi investor dari penipuan.
Time series sendiri memiliki arti sekumpulan data observasi yang dikoleksi berdasarkan kurun waktu tertentu. Contoh time series yang dulu sering kita jumpai adalah memprediksi jumlah pasien covid. Kala itu, prediksi jumlah pasien covid dapat digunakan oleh para ahli untuk mengambil keputusan kedepannya. Dan prediksinya bisa dalam bentuk harian atau bulanan.
PART #02: LOAD DATASET
dataset yang akan kita gunakan tidak tersedia di Kaggle. Jadi disini kita akan membuat dataset dengan mencarinya dari sumber lain. Dan untuk harga saham yang akan kita prediksi adalah saham google dengan kode “GOOGL”. Datanya kita ambil dari API Yahoo Finance (YFinance). Yfinance menyediakan data market yang disediakan oleh yahoo yang dapat didownload dengan menggunakan perintah dari python.
Langkah awal silakan diinstall terlebih dahulu API YFinance-nya.
Cukup ketik code pada figure 02 dan tunggu hasilnya sampai semua komponen selesai terinstall. Setelah selesai, kita import library yfinance dan tensorflow.
Kemudian, karena harga saham yang akan kita prediksi adalah google maka kita download dulu history data saham milik google. Caranya bisa kalian lihat pada code di figure 03.
Sebelum beranjak ke tahap berikutnya, mari kita sedikit bedah apa yang ada di dalam kurung tersebut. Yang pertama “GOOGL” adalah kode saham untuk google. Kemudian perintah “start” digunakan untuk menentukan tanggal awal data akan diambil, lalu “end” digunakan untuk menentukan tanggal akhir dari data yang akan diambil. Untuk “end” sendiri bersifat opsional. Jadi jika kalian tidak memasukkan perintah “end” maka data yang kita dapatkan akan berakhir sampai dengan tanggal kalender saat kalian membuat programnya. Selanjutnya “interval” adalah perintah untuk menentukan jangka waktu pengambilan data. Interval bisa berupa waktu harian, mingguan atau bulanan.
Untuk studi kasus ini, data yang digunakan adalah data dari awal tahun januari sampai 28 Februari 2023 dengan interval waktu 1 hari. Selanjutnya Langkah umum yang sering kita lakukan yaitu mengecek shape dari data yang kita miliki.
Terlihat bahwa kita memiliki 794 data dengan 6 fitur yang ada di dalamnya. Selanjutnya mari kita lihat fitur apa saja yang dimiliki oleh dataset ini.
Disini kita punya fitur ‘Open’, ‘High’, ‘Low’, ‘Close’, dan ‘Volume’. Mari kita pelajari sedikit arti dari fitur — fitur ini. Misalkan kita punya sesi trading dari jam 09:30 sampai jam 16:00. Nah, harga saham di jam 09:30 ini dinamakan ‘Open’ dan harga di jam 16:00 disebut ‘Close’. Nilai High dan Low ditentukan oleh tingkat sentiment masyarakat Ketika saham perusahaan diperdagangkan secara terbuka.
Disini kita bisa gunakan google sebagai contohnya. Ketika google mengumumkan event promo salah satu produknya, hal ini bisa membuat masyarakat memberikan harga tinggi di esok hari ketika perdagangan saham dibuka. Sebaliknya, jika server google mengalami gangguan atau produk yang mereka pasarkan bermasalah kemudian masyarakat mengeluh di sosial media, ini akan membuat nilai saham google anjlok pada hari berikutnya. Hal — hal seperti inilah salah satu contoh yang mempengaruhi naik turunnya harga saham atau yang dikenal dengan istilah ‘High’ dan ‘Low’.
‘Adj Close’ adalah penyesuaian harga penutupan saham yang masih mencerminkan harga saham tersebut setelah dilakukan beberapa Tindakan. Misalkan harga saham Google senilai USD 1750, tentu akan sangat susah bagi masyarakat untuk membeli 1 saham google. Sehingga dilakukan pemecahan menjadi 100 bagian dan harganya pun dibagi sama rata menjadi USD 17,5 agar mempermudah masyarakat untuk mendapatkan 1 lembar saham dari google. Dan yang terakhir, ‘Volume’ adalah pengukuran seberapa banyak jumlah saham yang diperdagangkan dalam kurun waktu tertentu.
Oke itu tadi penjelasan dari tiap — tiap fitur dari dataset ini. Selanjutnya mari kita lakukan sedikit penyesuaian terhadap dataset ini.
Selanjutnya kita bisa mengecek data pada tanggal terakhir dari dataset ini dengan menggunakan perintah ‘tail’.
Angka pada perintah tail menunjukkan jumlah data yang akan ditampilkan. Jika angka yang kita tetapkan 5, maka data yang tampil adalah 5 terbawah seperti yang terlihat pada gambar figure 08.
Langkah berikutnya adalah pengecekan null values dan deskripsi dari dataset.
Berikutnya, kita import library dari plotly untuk menampilkan grafik saham google. Dan untuk mode yang digunakan adalah lines dan data yang digunakan adalah ‘Close’.
Hasil dari code diatas bisa dilihat pada grafik dibawah ini. Terlihat bahwa harga ‘Close’ Google berada pada titik terendah pada bulan Maret 2020 dan beranjak meningkat dari awal Tahun 2021 dan mencapai harga tertinggi pada periode Juli 2021 sampai Januari 2022.
Kita juga bisa melihat trend dari volume dengan mengetik code pada figure 13.
Terlihat bahwa ‘Volume’ memiliki pola yang sama pada beberapa periode. Meskipun demikian, kita tidak bisa melihat trend naik turunnya harga saham dengan melihat ‘Volume’ karena secara definisi ‘Volume’ hanya menggambarkan jumlah pembelian saham pada periode waktu tertentu.
PART #03: DATA PREPROCESSING
Masuk ke tahap data preprocessing, kita import beberapa library tambahan yang dibutuhkan pada project ini yaitu MinMaxScaler, pickle, dan tqdm. MinMaxScaler mengurangi nilai minimum pada feature dan membaginya berdasarkan area. Area yang dimaksud adalah perbedaan jarak antara nilai asli maksimum dan nilai asli minimum. MinMaxScaler tidak mengubah informasi apapun yang terkandung di data asli.
Kemudian pickle adalah modul yang digunakan untuk membuat serial dan de-serializing sebuah struktur objek python. Atau dengan kata lain sebuah proses untuk mengkonversi sebuah objek python menjadi byte stream untuk disimpan ke dalam database.
Lalu ada tqdm yang fungsinya cukup simple yaitu membuat sebuah progress bar pada python. Jadi, tahap awal dari data preprocessing ini silakan ketik code dibawah untuk mengimport library — library ini.
Selanjutnya kita ambil feature ‘Close’ dan ‘Volume’ saja. Disini saya tampilkan cuma 5 data saja ya, kalau kalian mau lebih boleh — boleh aja.
Kemudian kita atur untuk alokasi testing datanya. Disini saya pakai data dengan rentang waktu dari bulan Oktober 2022 sebagai testing datanya. Jadi bisa dibilang kita pakai data dari 5 bulan terakhir (Oktober 2022 — Februari 2023) untuk dilakukan pengujian terhadap model kita nantinya.
Selanjutnya kita buat sebuah fungsi yang mengambil data frame dan feature length dan mengembalikannya ke ‘features’ dan ‘targets’.
Pada baris pertama, ‘data’ adalah dataset yang kita miliki yang berisi ‘Close’ dan ‘Volume’. Kemudian ‘feature_length’ adalah jumlah data point yang akan kita tentukan. Selanjutnya kita jalankan fungsi tersebut dengan mengetik code berikut ini.
Sekalian kita bisa langsung cek shape dari X dan Y yang telah kita buat.
Kita punya data berbentuk 3 dimensi pada X dan 1 dimensi pada Y. dimensi pertama adalah jumlah data yang kita miliki, dimensi kedua adalah feature_length yang kita pilih, dan dimensi ketiga adalah jumlah kolom dari data yang kita filter. Selanjutnya kita bagi features dan target tersebut dengan train test split.
Langsung dilanjutkan dengan pengecekan shape masing — masing.
Karena kita memiliki 3 dimensi sedangkan scaler hanya berfungsi terhadap fitur 2 dimensi. Maka kita buatkan sebuah fungsi agar scaler bisa berfungsi pada data yang memiliki lebih dari 2 dimensi.
Selanjutnya, mari kita fit-kan training dan testing data kita.
Untuk ‘target’, kita tambahkan perintah reshape agar datanya menjadi 2 dimensi. Selanjutnya Langkah seperti biasa, kita cek Kembali masing — masing shape-nya.
Sebelum masuk ke pembuatan model, Langkah terakhir kita buat 2 fungsi yang bertujuan untuk menyimpan objek dan memanggil kembali objek tersebut.
PART #04: CREATE MODEL
Sekarang kita sudah memasuki tahap pembuatan model. Pada tahap ini, kita menambahkan library ModelCheckpoint dan ReduceLROnPlateau. ReduceLROnPlateau berfungsi untuk menggurangi learning rate ketika tidak ada peningkatan pada nilai validation loss.
Pada studi kasus kali ini, kita menggunakan ‘elu’ sebagai activationnya. Berbeda dengan ‘relu’. ‘Elu’ memiliki nilai negatif yang mendorong nilai rata — rata activation mendekati 0. Untuk penggunaannya sama saja dengan relu yaitu kita tinggal panggil saja activationnya.
Untuk optimizernya kita akan gunakan SGD pada studi kasus ini karena setelah saya melakukan percobaan dengan membandingkan SGD dan Adam, SGD performanya lebih baik.
Selanjutnya mari kita fit-kan model kita. Untuk settingannya, saya hanya menggunakan 10 epochs karena datanya juga ga banyak — banyak banget.
Seperti biasa, tunggu saja prosesnya hingga selesai. Karena epochs kita sedikit seharusnya ga akan memakan banyak waktu untuk prosesnya. Kalau sudah selesai, jangan lupa kita load modelnya dengan perintah load_weights.
Setelah di load, langsung aja kita deklarasikan perintah untuk memprediksinya dengan perintah predict.
Kalau kalian ingat, sebelumnya kita telah men-scaled nilai targetnya sebelum pembuatan model. Maka sekarang hasil prediksinya kita scaled juga agar Langkah yang kita lakukan tetap konsisten.
Dilanjutkan dengan menampilkan shape-nya (figure 34), disini hasil prediksinya berbentuk 2 dimensi. Nah, disini yang kita butuhkan hanya 1 dimensi saja. Jadi kita gunakan fungsi squeeze untuk mengubah dimensinya menjadi 1 dimensi aja.
Selanjutnya kita tampilkan hasil prediksi dari model yang sudah kita buat dengan nilai aslinya sebagai perbandingan performa dari model kita. Disini tipe grafik yang kita gunakan adalah garis (lines). Code dan hasilnya bisa kalian lihat pada figure 36 dan 37 dibawah ini.
Garis berwarna merah menunjukkan hasil prediksi sedangkan yang berwarna biru menunjukkan nilai aktual. Disini terlihat bahwa grafik dari hasil prediksi masih belum bisa mengimbangi atau menyesuaikan ritme dari nilai aktual. Kita bisa cek performa grafiknya menggunakan keseluruhan dataset tapi sebelum itu kita perlu gabung dulu training data dengan testing datanya. Kita bisa gunakan perintah concatenate untuk penggabungannya, dan selanjutnya langkahnya sama dengan apa yang kita lakukan setelah load weights. Jadi silakan di ketik code — code dibawah ini.
Hasil dari sejumlah code pada figure 38 bisa kalian lihat di figure 39 dibawah ini. Secara keseluruhan bisa kalian lihat bahwa nilai prediksinya sedikit mampu mengikuti ritme dari nilai aktualnya hanya saja tidak signifikan. Jadi pada part berikutnya kita akan bahas fitur apa yang bisa kita gunakan untuk meningkatkan performa model kita.
PART #05: EVALUATE MODEL
Pada part ini, kita akan menambahkan satu feature ke dalam dataset untuk mengimprove performa prediksinya. Fitur yang akan kita ambil adalah Relative Strength Index atau RSI. RSI adalah sebuah indicator yang digunakan dalam analisis teknikal. RSI mengukur kecepatan dan besarnya perubahan harga sekuritas untuk mengevaluasi kondisi overvalued atau undervalued pada sekuritas tersebut.
Untuk pengambilan datanya sendiri kita masih tetap menggunakan sumber dari Yahoo Finance jadi langsung aja diketik code dibawah ini.
Baris ke-3 pada code adalah waktu dimulainya pengambilan data. Disini saya mengambil data dari bulan Agustus 2004. Kemudian baris ke 6 menunjukkan periode dari RSI itu sendiri. Nilai terbaik dari periode RSI berkisar antara 2–6 dan nilai standar yang pas untuk segala situasi adalah 14. Pada studi kasus ini, semua rentang nilai tersebut sudah saya coba dan hasil terbaik yang saya dapatkan adalah di angka 5. Kemudian baris ke 7 sampai 13 adalah rumus untuk menghitung nilai RSI nya. Jujur saya tidak terlalu paham mengenai perhitungannya jadi saya ga bisa banyak menjelaskan terkait rumusnya disini (maklum bukan pakar ekonomi, #haha).
Oke, setelah kita mendapatkan data RSI-nya langsung aja kita konversi menjadi sebuah dataframe dengan tanggal (date) sebagai indexnya dan nilai RSI sebagai valuenya.
Bila kalian perhatikan, date pada RSI ini masih berisi data waktu (00:00:00–04:00), ini akan kita hapus supaya sama dengan tipe data date pada data sebelumnya.
Nantinya datanya akan berubah seperti pada figure 43 dibawah ini.
Setelah datanya sesuai, selanjutnya kita gabungkan data awal dengan data yang sudah berisi RSI dengan menggunakan perintah merge. Dan hasil akhir dari datanya akan berisikan fitur ‘Close’, ‘Volume’, dan ‘RSI’.
Selanjutnya kita akan latih ulang (re-train) modelnya dengan data baru yang berisikan RSI. Untuk codenya sendiri sebenarnya sama dengan code training sebelumnya. Langkahnya diawali dengan penentuan rentang waktu untuk test dataset. Sama seperti sebelumnya, disini kita atur waktunya dari bulan Oktober 2022.
Berhubung Langkah selanjutnya sama dengan Langkah sebelumnya. Jadi disini saya hanya akan menampilkan baris codingannya saja yang bisa kalian ikuti baris per barisnya. Nanti diakhir akan saya jelaskan kesimpulan dari hasil yang kita dapat.
Langkah — Langkah diatas adalah Langkah untuk mengkonfigurasi ulang training dan testing data. Selanjutnya adalah tahapan untuk membuat ulang modelnya. Tahapan ini juga Langkah — langkahnya sama dengan Langkah pembuatan model sebelumnya (sebelum adanya RSI). Jadi silakan kalian lanjut lagi mengcoding baris — baris code dibawah ini sampai akhir.
Dan akhirnya kita tiba di akhir baris coding. Gambar terakhir dari figure 56 adalah hasil prediksi dari dataset yang telah kita tambahkan RSI. Untuk lebih jelasnya, disini saya bandingkan hasil tersebut dengan hasil dari dataset yang tanpa RSI melalui figure 57 dibawah.
Jika kalian perhatikan, area yang saya highlight dengan kotak warna hijau adalah area yang kita prediksi. Terlihat bahwa kurva nilai prediksi dari dataset yang berisi RSI sudah mulai bisa mengikuti kurva nilai aktual. Ini membuktikan bahwa data RSI berpengaruh besar dalam pembuatan model time series harga saham walaupun memang masih belum bisa menyerupai persis seperti nilai aktualnya.