Saham Batas Turun & Naik Bot Telegram Spreadsheet

Saham Batas Turun & Naik Bot Telegram Spreadsheet

A. Pengantar

Versi script dinamis membaca berdasarkan nama kolom juga bisa (misalnya cari kolom yang berjudul "Batas Turun" di baris pertama) — tapi harus pakai logika tambahan untuk deteksi judul di baris pertama (lebih rumit). Perlu memperhatikan nama kolom secara akurat jika kamu pakai metode parsing seperti mencari dengan .find() atau objek header.

Tapi untuk efisiensi, lebih mudah jika kamu tetap konsisten dengan urutan kolom saja dan tahu indeks kolom yang digunakan seperti sekarang. Menggunakan getRange(row, column) atau getValues(), maka Google Apps Script akan merujuk berdasarkan indeks angka (mulai dari 1 untuk getRange, mulai dari 0 untuk array hasil getValues()).

šŸ“Œ Apakah Penulisan "Batas Turun" dan "Batas Naik" Harus Pakai Spasi atau Huruf Besar?

✨ Jawaban:
Tidak berpengaruh langsung, selama kamu tidak mengakses data berdasarkan nama kolom di dalam script.

Google Apps Script biasanya membaca data berdasarkan indeks kolom (yaitu urutan angka, bukan nama kolom). Artinya, kamu bebas menulis nama kolom di spreadsheet seperti "Batas Turun", "batas turun", "batasturun", atau varian lainnya — selama kamu tahu posisi kolom tersebut berdasarkan urutan kolom.

šŸ”¢ Contoh Indeks Kolom:

Kolom Huruf Judul Index (mulai dari 0)
1 A Kode Saham 0
2 B Harga 1
3 C Batas Turun 2
4 D Batas Naik 3

✔️ Jadi, pastikan kamu tahu posisi kolom berdasarkan urutannya, bukan hanya berdasarkan namanya.

B. Buka Google Sheets:
  1. Buka Google Sheets:
  2. Buka Editor Apps Script:
    • Klik menu Extensions (Ekstensi).
    • Pilih Apps Script.
  3. Tempel atau tulis kode program:
    • Hapus kode default (jika ada), lalu tempel kode baru yang kamu inginkan.
  4. Simpan proyek:
    • Klik ikon disket šŸ’¾ atau tekan Ctrl + S.
    • Pastikan tidak ada error dalam kode.
    • Ubah nama proyek di kiri atas, misalnya: Script Otomatisasi.
  5. Jalankan fungsi dari kode:
    • Klik tombol Run (ikon ▶️).
    • Pilih nama fungsi yang ingin dijalankan (jika ada lebih dari satu).
  6. Review dan izinkan akses:
    • Google akan meminta izin saat pertama kali menjalankan skrip.
    • Pilih akun Google kamu.
    • Klik Lanjutkan atau Izinkan.
    • Jika muncul pesan “Google hasn’t verified this app”:
      • Klik Advanced (Lanjutan).
      • Klik Go to project name (unsafe).
    • Izinkan akses sesuai permintaan (ini hanya perlu sekali, kecuali kamu mengubah izin/scope).
  7. Kembali ke spreadsheet:
    • Setelah proses otorisasi selesai, kamu bisa menjalankan skrip langsung dari spreadsheet atau editor.

bisa bikin fungsi kustom, trigger otomatis, atau macro di sini. Kalau mau trigger otomatis (misalnya skrip jalan tiap jam), buka Triggers → Add Trigger → atur sesuai kebutuhan.

Catatan PENTING (belum diedit) dari 7 langkah di atas

Catatan diingat: advance > go to untittled project (unsafe) > ada 2 yang perlu dicentang untuk ijin berhasil.

BUKAN: Untitled Project > got it

C. Fitur Apps Script

Buka docs.google.com > Spreadsheets > Extensions > Apps Script > klik ikon jam ⏰ ("Triggers") > Klik Triggers → terbuka halaman Triggers > Tombol di kanan bawah → + Add Trigger:

✅ Cara Set Trigger di Google Sheets: Langkah Demi Langkah

Supaya skrip kamu bisa berjalan otomatis, kamu perlu menambahkan trigger di Google Apps Script.

šŸ”§ Langkah-langkah Membuat Trigger

  1. Buka Apps Script Editor
    Di Google Sheets, klik: Extensions → Apps Script
  2. Klik Ikon Triggers
    Di sebelah kiri, klik ikon ⏰ (jam alarm) → akan terbuka halaman "Triggers".
  3. Klik + Add Trigger
    Tombol ini berada di kanan bawah layar.
  4. Pilih Pengaturan Trigger
    • Choose which function to run: Pilih fungsi yang ingin dijalankan, misalnya: myFunction
    • Choose which deployment should run: Biarkan default: Head
    • Select event source:
      • Time-driven → Berdasarkan waktu (jadwal otomatis)
      • From spreadsheet → Berdasarkan aktivitas di sheet (dibuka, diedit, form)
    • Select type of time-based trigger:
      Jika memilih Time-driven, pilih frekuensi: tiap menit, jam, hari, minggu, dll.
    • Failure notification settings:
      Pilih apakah ingin mendapat email notifikasi jika terjadi error.
  5. Klik Save
    Klik Save → Google akan meminta izin jika diperlukan. Selesai! Trigger sudah aktif.

šŸ“Œ Contoh Trigger Paling Umum

  • Jalan otomatis setiap 1 jam:
    Event source: Time-driven
    Type: Hour timer
    Interval: Every hour
  • Jalan otomatis saat sheet di-edit:
    Event source: From spreadsheet
    Event type: On edit

🧹 Cek & Hapus Trigger

Masih di menu Triggers, kamu bisa melihat daftar trigger yang aktif.

Untuk menghapus trigger, klik ikon šŸ—‘️ di samping nama trigger yang ingin dihapus.

D. Alternatif Selain GOOGLEFINANCE()

Harga saham dapat diambil (fetch) dari API pihak ketiga (misalnya API tidak resmi Yahoo Finance atau hasil scraping file CSV), lalu diimpor ke dalam spreadsheet menggunakan Google Apps Script atau add-on eksternal.

E. Bot Telegram

Siapkan Bot Telegram

  1. Buka aplikasi Telegram di perangkat Anda.
  2. Cari akun resmi (biru centang) @BotFather.
  3. Ketik perintah /newbot untuk membuat bot baru.
  4. Ikuti instruksi untuk memberi nama dan username.bot.
  5. Panjang contoh token 47 karakter, catat Token API yang diberikan. Token ini diperlukan untuk menghubungkan bot dengan aplikasi Anda.
  6. Buka di browser, https://api.telegram.org/bot[YOUR_TOKEN]/getUpdatesberhasil jika: {"ok":true,"result":[]}
  7. Buka di browser, https://api.telegram.org/bot[YOUR_TOKEN]/getMeberhasil jika: {"ok":true,"result":{"id":xxxxxxxxxx,"is_bot":true,"first_name":"NameBot","username":"UserNameBot","can_join_groups":true,"can_read_all_group_messages":false,"supports_inline_queries":false,"can_connect_to_business":false,"has_main_web_app":false}}
F. Kode GOOGLE APPS SCRIPT v1

Kosong

Script di Google Apps Script

const TELEGRAM_TOKEN = "123456789:ABCdEfGhIjKlMnOpQRsTuvWxYz"; const TELEGRAM_CHAT_ID = "123456789"; // Ganti dengan chat ID kamu const THRESHOLD = 400; // Batas bawah harga function checkStockPrice() { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); // Ganti sesuai nama sheet const price = sheet.getRange("B1").getValue(); if (price < THRESHOLD) { const message = `🚨 Harga saham turun di bawah batas!\nšŸ’° Harga sekarang: ${price}`; sendTelegramAlert(message); } } function sendTelegramAlert(message) { const url = `https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage`; const payload = { chat_id: TELEGRAM_CHAT_ID, text: message }; const options = { method: "post", contentType: "application/json", payload: JSON.stringify(payload) }; UrlFetchApp.fetch(url, options); }
G. Kode GOOGLE APPS SCRIPT v3
const TELEGRAM_TOKEN = "123456789:ABCdEfGhIjKlMnOpQRsTuvWxYz"; // Ganti token kamu const TELEGRAM_CHAT_ID = "123456789"; // Ganti dengan chat ID kamu function checkAllStocks() { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); const data = sheet.getDataRange().getValues(); // Ambil semua data let alerts = []; for (let i = 1; i < data.length; i++) { // Mulai dari baris kedua const kodeSaham = data[i][0]; const hargaSaatini = parseFloat(data[i][2]); const batasTurun = parseFloat(data[i][4]); const batasNaik = parseFloat(data[i][5]); if (!isNaN(harga)) { if (!isNaN(batasTurun) && harga < batasTurun) { alerts.push(`šŸ”» ${nama} TURUN: ${harga} (batas: ${batasTurun})`); } if (!isNaN(batasNaik) && harga > batasNaik) { alerts.push(`šŸ”ŗ ${nama} NAIK: ${harga} (batas: ${batasNaik})`); } } } if (alerts.length > 0) { const message = `šŸ“Š ALERT HARGA SAHAM:\n` + alerts.join("\n"); sendTelegramAlert(message); } } function sendTelegramAlert(message) { const url = `https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage`; const payload = { chat_id: TELEGRAM_CHAT_ID, text: message }; const options = { method: "post", contentType: "application/json", payload: JSON.stringify(payload) }; UrlFetchApp.fetch(url, options); }
H. Kode GOOGLE APPS SCRIPT v5

⚙️ Apa yang Dilakukan Script Ini

Script ini dirancang untuk mengirim alert hanya satu kali setiap kali harga melewati batas yang sudah ditentukan. Dengan cara ini, kamu tidak akan menerima alert berulang-ulang setiap script dijalankan secara berkala.

  • 🚨 Mengirim alert hanya sekali saat harga melewati batas Naik atau Turun.
  • Menandai status dengan kata "Naik" atau "Turun" untuk mencegah pengiriman alert berulang setiap periode (misalnya setiap 10 menit).
  • šŸ”„ Jika harga kembali ke zona normal, kolom Status akan dikosongkan sehingga memungkinkan script untuk mengirim alert lagi jika kondisi yang sama terulang di lain waktu.

✅ Ringkasan Fungsi Script

Script ini hanya akan mengirim alert satu kali untuk setiap kondisi (Naik atau Turun), dengan cara kerja berikut:

  1. Ketika harga melewati batas, script akan:
    • Mengirim alert ke Telegram.
    • Menandai kolom Status dengan nilai "Naik" atau "Turun".
  2. Pada eksekusi berikutnya (misalnya 10 menit kemudian), script akan melewati saham yang statusnya sudah "Naik" atau "Turun" sehingga tidak mengirim alert ulang.
  3. Jika harga kembali normal, maka status akan di-reset menjadi kosong (""). Ini membuat script siap mengirim alert lagi jika harga melewati batas di kemudian hari.

šŸ” Ilustrasi Logika Pengiriman Alert

Harga Sekarang Batas Turun Status Sebelumnya Hasil
390 400 (kosong) šŸ”” Kirim alert "Turun" + set status = "Turun"
385 400 "Turun" 🚫 Tidak kirim ulang
410 400 "Turun" šŸ”„ Reset status jadi kosong
395 400 (kosong) šŸ”” Kirim alert lagi

šŸ“Œ Versi Lanjutan (Opsional)

Jika kamu ingin mengembangkan script ini lebih jauh, beberapa opsi lanjutan yang bisa ditambahkan antara lain:

  • 🟨 Memisahkan kolom status menjadi Status Naik dan Status Turun agar riwayat kondisi lebih jelas.
  • šŸ“… Menambahkan kolom tanggal dan jam khusus untuk mencatat kapan alert dikirim.
  • šŸ“‹ Menyimpan log ke sheet terpisah khusus untuk riwayat alert.
  • šŸ”„ Menambahkan penanda apakah alert sudah dibaca atau ditindaklanjuti secara manual.

✅ SCRIPT GOOGLE APPS SCRIPT

const TELEGRAM_TOKEN = "123456789:ABCdEfGhIjKlMnOpQRsTuvWxYz"; // Ganti token kamu const TELEGRAM_CHAT_ID = "123456789"; // Ganti dengan chat ID kamu function checkAllStocks() { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); const data = sheet.getDataRange().getValues(); let alerts = []; for (let i = 1; i < data.length; i++) { const nama = data[i][0]; const harga = parseFloat(data[i][1]); const batasTurun = parseFloat(data[i][2]); const batasNaik = parseFloat(data[i][3]); const status = data[i][4]; // Status sebelumnya if (!isNaN(harga)) { if (!isNaN(batasTurun) && harga < batasTurun && status !== "Turun") { alerts.push(`šŸ”» ${nama} TURUN: ${harga} (batas: ${batasTurun})`); sheet.getRange(i + 1, 5).setValue("Turun"); // Kolom E (index 5) } else if (!isNaN(batasNaik) && harga > batasNaik && status !== "Naik") { alerts.push(`šŸ”ŗ ${nama} NAIK: ${harga} (batas: ${batasNaik})`); sheet.getRange(i + 1, 5).setValue("Naik"); } else if ( (status === "Turun" && harga >= batasTurun) || (status === "Naik" && harga <= batasNaik) ) { // Reset status jika harga kembali normal sheet.getRange(i + 1, 5).setValue(""); } } } if (alerts.length > 0) { const message = `šŸ“Š ALERT HARGA SAHAM:\n` + alerts.join("\n"); sendTelegramAlert(message); } } function sendTelegramAlert(message) { const url = `https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage`; const payload = { chat_id: TELEGRAM_CHAT_ID, text: message }; const options = { method: "post", contentType: "application/json", payload: JSON.stringify(payload) }; UrlFetchApp.fetch(url, options); }
I. Kode GOOGLE APPS SCRIPT v7

šŸ“ 1. Di Mana Letak Logs?

Semua log disimpan otomatis di spreadsheet Google Sheets, bukan hanya di Telegram. Script akan secara otomatis membuat atau menggunakan sheet baru bernama Log Alert. Setiap kali ada alert (baik Naik maupun Turun), log akan ditambahkan sebagai baris baru di sheet tersebut.

Contoh isi sheet Log Alert:

Tanggal & Waktu Saham Kondisi Harga Batas
2025-07-13 16:42:01 AAPL Turun 135 140
2025-07-13 17:10:00 TSLA Naik 770 750

šŸ”„ 2. Apakah Spreadsheet Akan Terisi Otomatis Saat Harga Berubah?

Kolom Harga (kolom B) harus diperbarui secara otomatis agar script dapat mendeteksi perubahan. Beberapa cara untuk memperbarui harga secara otomatis:

  • Menggunakan formula seperti =GOOGLEFINANCE(...) (meskipun dukungannya terbatas untuk saham IDX).
  • Atau mengimpor harga dari API melalui Apps Script atau add-on eksternal.

Script alert hanya memantau data harga yang sudah ada di kolom B. Jadi, pastikan harga di kolom B berubah secara berkala agar script bekerja sesuai fungsi.

🚫 3. Jika Kolom "Batas Turun" atau "Batas Naik" Tidak Diisi, Apakah Tetap Kirim Alert?

Tidak. Jika kolom Batas Turun atau Batas Naik dibiarkan kosong, maka parseFloat() akan menghasilkan NaN dan kondisi if (!isNaN(...)) akan gagal. Hasilnya: baris tersebut tidak akan diproses dan alert tidak akan dikirim.

Artinya:

  • Jika hanya ingin memantau kenaikan, isi hanya kolom Batas Naik.
  • Jika hanya ingin memantau penurunan, isi hanya kolom Batas Turun.
  • Jika keduanya kosong, maka baris data akan diabaikan oleh script.

šŸ“¤ 4. Apakah Alert ke Telegram Bisa Disalin atau Diunduh?

Bisa disalin: Pesan alert yang dikirim ke Telegram berupa teks biasa, sehingga bisa dicopy-paste layaknya chat biasa.

šŸ“Ž Bisa diunduh (opsional): Jika diperlukan, script dapat dimodifikasi untuk:

  • Mengirim alert sebagai file .txt.
  • Mengirim link ke Google Sheet tempat log disimpan.

Namun, secara default alert dikirim sebagai pesan teks Telegram, bukan file.

KODE GOOGLE APPS SCRIPT

const TELEGRAM_TOKEN = "123456789:ABCdEfGhIjKlMnOpQRsTuvWxYz"; // Ganti dengan milikmu const TELEGRAM_CHAT_ID = "123456789"; // Ganti dengan chat ID kamu function checkAllStocks() { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); const logSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Log Alert") || SpreadsheetApp.getActiveSpreadsheet().insertSheet("Log Alert"); const data = sheet.getDataRange().getValues(); const now = new Date(); const alerts = []; for (let i = 1; i < data.length; i++) { const nama = data[i][0]; const harga = parseFloat(data[i][1]); const batasTurun = parseFloat(data[i][2]); const batasNaik = parseFloat(data[i][3]); const statusTurun = data[i][4]; const waktuTurun = data[i][5]; const statusNaik = data[i][6]; const waktuNaik = data[i][7]; const row = i + 1; if (!isNaN(harga)) { // Cek TURUN if (!isNaN(batasTurun)) { if (harga < batasTurun && statusTurun !== "Terkirim") { const msg = `šŸ”» ${nama} TURUN ke ${harga} (batas: ${batasTurun})`; alerts.push(msg); sheet.getRange(row, 5).setValue("Terkirim"); // Status Turun sheet.getRange(row, 6).setValue(now); // Waktu Turun logSheet.appendRow([now, nama, "Turun", harga, batasTurun]); } else if (harga >= batasTurun && statusTurun === "Terkirim") { sheet.getRange(row, 5).setValue(""); // Reset Status Turun sheet.getRange(row, 6).setValue(""); } } // Cek NAIK if (!isNaN(batasNaik)) { if (harga > batasNaik && statusNaik !== "Terkirim") { const msg = `šŸ”ŗ ${nama} NAIK ke ${harga} (batas: ${batasNaik})`; alerts.push(msg); sheet.getRange(row, 7).setValue("Terkirim"); // Status Naik sheet.getRange(row, 8).setValue(now); // Waktu Naik logSheet.appendRow([now, nama, "Naik", harga, batasNaik]); } else if (harga <= batasNaik && statusNaik === "Terkirim") { sheet.getRange(row, 7).setValue(""); // Reset Status Naik sheet.getRange(row, 8).setValue(""); } } } } if (alerts.length > 0) { const message = `šŸ“Š ALERT HARGA SAHAM:\n` + alerts.join("\n"); sendTelegramAlert(message); } } function sendTelegramAlert(message) { const url = `https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage`; const payload = { chat_id: TELEGRAM_CHAT_ID, text: message }; const options = { method: "post", contentType: "application/json", payload: JSON.stringify(payload) }; UrlFetchApp.fetch(url, options); }
J. Kode GOOGLE APPS SCRIPT v9

✅ Versi Terbaru Script Alert Saham

Script Google Apps Script terbaru ini akan otomatis mengirim alert ke Telegram sebagai .txt, mencatat log di sheet, dan mencegah pengiriman berulang dengan memanfaatkan kolom status.

šŸ”§ Persiapan Sebelum Script

  • Bot Telegram kamu harus aktif.
  • Siapkan token Bot dan chat ID Telegram.
  • Spreadsheet kamu harus memiliki struktur kolom seperti ini:
Nama Harga Batas Turun Batas Naik Status Turun Waktu Turun Status Naik Waktu Naik

šŸ“ Hasil di Telegram

Jika kondisi terpenuhi, kamu akan menerima file alert_saham.txt berisi daftar alert, contohnya:

šŸ”» GOTO TURUN ke 74 (batas: 80)
        šŸ”ŗ BBCA NAIK ke 9500 (batas: 9400)

šŸ¤” Contoh Format Pesan Markdown ke Telegram

Jika kamu ingin hanya mengirim pesan (bukan file), format markdown bisa seperti ini:

šŸ“Š *ALERT SAHAM!*

        šŸ”» **GOTO** TURUN ke `74` (batas: 80)  
        šŸ”ŗ **BBCA** NAIK ke `9500` (batas: 9400)

Hasil tampil di Telegram:

šŸ“Š ALERT SAHAM!
        šŸ”» GOTO TURUN ke 74 (batas: 80)
        šŸ”ŗ BBCA NAIK ke 9500 (batas: 9400)

✅ GOOGLE APPS SCRIPT: Kirim Alert Sebagai File .txt

const TELEGRAM_TOKEN = "123456789:ABCdEfGhIjKlMnOpQRsTuvWxYz"; // Ganti token const TELEGRAM_CHAT_ID = "123456789"; // Ganti chat ID kamu function checkAllStocks() { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); const logSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Log Alert") || SpreadsheetApp.getActiveSpreadsheet().insertSheet("Log Alert"); const data = sheet.getDataRange().getValues(); const now = new Date(); const alerts = []; for (let i = 1; i < data.length; i++) { const nama = data[i][0]; const harga = parseFloat(data[i][1]); const batasTurun = parseFloat(data[i][2]); const batasNaik = parseFloat(data[i][3]); const statusTurun = data[i][4]; const statusNaik = data[i][6]; const row = i + 1; if (!isNaN(harga)) { // Turun if (!isNaN(batasTurun)) { if (harga < batasTurun && statusTurun !== "Terkirim") { alerts.push(`šŸ”» ${nama} TURUN ke ${harga} (batas: ${batasTurun})`); sheet.getRange(row, 5).setValue("Terkirim"); sheet.getRange(row, 6).setValue(now); logSheet.appendRow([now, nama, "Turun", harga, batasTurun]); } else if (harga >= batasTurun && statusTurun === "Terkirim") { sheet.getRange(row, 5).setValue(""); sheet.getRange(row, 6).setValue(""); } } // Naik if (!isNaN(batasNaik)) { if (harga > batasNaik && statusNaik !== "Terkirim") { alerts.push(`šŸ”ŗ ${nama} NAIK ke ${harga} (batas: ${batasNaik})`); sheet.getRange(row, 7).setValue("Terkirim"); sheet.getRange(row, 8).setValue(now); logSheet.appendRow([now, nama, "Naik", harga, batasNaik]); } else if (harga <= batasNaik && statusNaik === "Terkirim") { sheet.getRange(row, 7).setValue(""); sheet.getRange(row, 8).setValue(""); } } } } if (alerts.length > 0) { const textContent = alerts.join("\n"); sendTelegramFile(textContent, "alert_saham.txt"); } } // šŸ“Ø Fungsi untuk mengirim file .txt ke Telegram function sendTelegramFile(textContent, filename) { const blob = Utilities.newBlob(textContent, "text/plain", filename); const formData = { chat_id: TELEGRAM_CHAT_ID, document: blob }; const options = { method: "post", payload: formData, muteHttpExceptions: true }; UrlFetchApp.fetch(`https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendDocument`, options); }
K. Kode GOOGLE APPS SCRIPT v11 simpan file.txt di folder

šŸŽÆ Fitur yang Akan Kita Buat

Kita akan membuat sistem yang secara otomatis mengirimkan file .txt berisi alert ke Telegram dengan nama file yang terformat otomatis, lalu menyimpan file yang sama ke Google Drive, sekaligus mencatat log di spreadsheet agar semua aktivitas tercatat rapi dan menghindari pengiriman alert duplikat dengan cara memantau status per baris saham.

✅ Fitur Utama

  • Mengirim file .txt berisi alert ke Telegram
  • Nama file otomatis mengikuti format: alert_YYYYMMDD_HHMM.txt
  • File yang sama akan disimpan otomatis ke Google Drive
  • Mencatat log pengiriman di sheet Log Alert
  • Menghindari alert duplikat dengan status per baris saham

šŸ“ Hasilnya

  1. Di Telegram:
    Kamu akan menerima file .txt dengan nama seperti:
    alert_20250713_1659.txt
    dengan isi file misalnya:
    šŸ”» GOTO TURUN ke 74 (batas: 80)
            šŸ”ŗ BBCA NAIK ke 9500 (batas: 9400)
  2. Di Google Drive:
    File yang sama akan otomatis disimpan di folder Google Drive kamu.
  3. Di Spreadsheet:
    • Sheet1: Status dan waktu kirim akan diperbarui otomatis.
    • Sheet Log Alert: Semua alert akan dicatat (waktu, saham, arah, harga, dan batas).

✅ GOOGLE APPS SCRIPT: Kirim .txt ke Telegram + Simpan ke Drive

const TELEGRAM_TOKEN = "123456789:ABCdEfGhIjKlMnOpQRsTuvWxYz"; // Ganti token const TELEGRAM_CHAT_ID = "123456789"; // Ganti chat ID function checkAllStocks() { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); const logSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Log Alert") || SpreadsheetApp.getActiveSpreadsheet().insertSheet("Log Alert"); const data = sheet.getDataRange().getValues(); const now = new Date(); const alerts = []; for (let i = 1; i < data.length; i++) { const nama = data[i][0]; const harga = parseFloat(data[i][1]); const batasTurun = parseFloat(data[i][2]); const batasNaik = parseFloat(data[i][3]); const statusTurun = data[i][4]; const statusNaik = data[i][6]; const row = i + 1; if (!isNaN(harga)) { // Turun if (!isNaN(batasTurun)) { if (harga < batasTurun && statusTurun !== "Terkirim") { alerts.push(`šŸ”» ${nama} TURUN ke ${harga} (batas: ${batasTurun})`); sheet.getRange(row, 5).setValue("Terkirim"); sheet.getRange(row, 6).setValue(now); logSheet.appendRow([now, nama, "Turun", harga, batasTurun]); } else if (harga >= batasTurun && statusTurun === "Terkirim") { sheet.getRange(row, 5).setValue(""); sheet.getRange(row, 6).setValue(""); } } // Naik XXXXXXXX ADA SALAH DI SINI !!!!!!!! if (!isNaN(batasNaik)) { if (harga > batasNaik && statusNaik !== "Terkirim") { alerts.push(`šŸ”ŗ ${nama} NAIK ke ${harga} (batas: ${batasNaik})`); sheet.getRange(row, 7).setValue("Terkirim"); sheet.getRange(row, 8).setValue(now); logSheet.appendRow([now, nama, "Naik", harga, batasNaik]); } else if (harga <= batasNaik && statusNaik === "Terkirim") { sheet.getRange(row, 7).setValue(""); sheet.getRange(row, 8).setValue(""); } } } } if (alerts.length > 0) { const textContent = alerts.join("\n"); const filename = generateTimestampedFilename(); // alert_YYYYMMDD_HHMM.txt // Simpan ke Google Drive const file = DriveApp.createFile(filename, textContent, MimeType.PLAIN_TEXT); // Kirim file ke Telegram sendTelegramFile(file, filename); } } // 🧠 Fungsi membuat nama file alert_YYYYMMDD_HHMM.txt function generateTimestampedFilename() { const now = new Date(); const pad = n => n.toString().padStart(2, '0'); const yyyy = now.getFullYear(); const mm = pad(now.getMonth() + 1); const dd = pad(now.getDate()); const hh = pad(now.getHours()); const min = pad(now.getMinutes()); return `alert_${yyyy}${mm}${dd}_${hh}${min}.txt`; } // šŸ“¤ Kirim file dari Drive ke Telegram function sendTelegramFile(file, filename) { const blob = file.getBlob().setName(filename); const formData = { chat_id: TELEGRAM_CHAT_ID, document: blob }; const options = { method: "post", payload: formData, muteHttpExceptions: true }; const response = UrlFetchApp.fetch(`https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendDocument`, options); Logger.log(response.getContentText()); }
L. Kode GOOGLE APPS SCRIPT v13 simpan file.txt di folder khusus, folder drive perlu API

Script Agar File .txt Disimpan di Folder Tertentu di Google Drive

Sekarang kita akan memastikan file .txt yang berisi alert tidak lagi disimpan di folder root Google Drive, melainkan di folder khusus yang sudah kamu tentukan.

✅ Langkah-Langkah

šŸ”¹ 1. Buat Folder Khusus di Google Drive

Buat folder baru di Google Drive, misalnya dengan nama Alert Saham

Setelah folder dibuat, klik kanan pada folder tersebut dan salin ID folder dari URL.

Contoh URL folder:

https://drive.google.com/drive/folders/1ABCdefGhIJklmnOpQRsTUvWxYz

ID folder kamu adalah:

1ABCdefGhIJklmnOpQRsTUvWxYz

šŸ”¹ 2. Masukkan ID Folder ke Dalam Script

Tambahkan ID folder tersebut ke dalam script kamu, misalnya:

const TELEGRAM_TOKEN = "123456789:ABCdEfGhIjKlMnOpQRsTuvWxYz"; // Token bot kamu
        const TELEGRAM_CHAT_ID = "123456789"; // Chat ID Telegram
        const DRIVE_FOLDER_ID = "1ABCdefGhIJklmnOpQRsTUvWxYz"; // ID folder Google Drive

šŸŽÆ Hasilnya:

  • šŸ” Setiap alert akan dikirim ke Telegram dalam bentuk file.
  • šŸ“ File otomatis disimpan di folder Google Drive yang sudah kamu tentukan (bukan di folder root).
  • šŸ“„ Nama file akan mengikuti format: alert_20250713_1705.txt

✅ SCRIPT SIMPAN DI FOLDER KHUSUS

const TELEGRAM_TOKEN = "8050614158:AAGnHHBERuADp2bBFl3PHsaFSuctLol6yVM"; // Ganti token bot kamu const TELEGRAM_CHAT_ID = "8050614158"; // Ganti chat ID kamu const DRIVE_FOLDER_ID = "1409jayTYfZgTQZPDkzfGmvofngiw5FVs"; // Ganti dengan ID folder Google Drive kamu function checkAllStocks() { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); const logSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Log Alert") || SpreadsheetApp.getActiveSpreadsheet().insertSheet("Log Alert"); const data = sheet.getDataRange().getValues(); const now = new Date(); const alerts = []; for (let i = 1; i < data.length; i++) { const row = i + 1; const kode = data[i][1]; // Kode Saham (kolom B) const nama = data[i][2]; // Nama Emiten (kolom C) const hargaRaw = data[i][3]; // Harga Saat Ini (kolom D) const batasTurunRaw = data[i][4]; // Batas Turun (kolom E) const batasNaikRaw = data[i][5]; // Batas Naik (kolom F) const statusTurun = data[i][6]; // Status Turun (kolom G) const statusNaik = data[i][7]; // Status Naik (kolom H) const harga = parseFloat(hargaRaw); const batasTurun = parseFloat(batasTurunRaw); const batasNaik = parseFloat(batasNaikRaw); if (!isNaN(harga)) { // šŸ”» TURUN if (!isNaN(batasTurun)) { if (harga < batasTurun && statusTurun !== "Terkirim") { alerts.push(`šŸ”» ${kode} - ${nama} TURUN ke ${harga} (batas: ${batasTurun})`); sheet.getRange(row, 7).setValue("Terkirim"); // Kolom G logSheet.appendRow([new Date(), kode, "Turun", harga, batasTurun]); } else if (harga >= batasTurun && statusTurun === "Terkirim") { sheet.getRange(row, 7).setValue(""); } } // šŸ”ŗ NAIK if (!isNaN(batasNaik)) { if (harga > batasNaik && statusNaik !== "Terkirim") { alerts.push(`šŸ”ŗ ${kode} - ${nama} NAIK ke ${harga} (batas: ${batasNaik})`); sheet.getRange(row, 8).setValue("Terkirim"); // Kolom H logSheet.appendRow([new Date(), kode, "Naik", harga, batasNaik]); } else if (harga <= batasNaik && statusNaik === "Terkirim") { sheet.getRange(row, 8).setValue(""); } } } } if (alerts.length > 0) { const textContent = alerts.join("\n"); const filename = generateTimestampedFilename(); // Simpan ke folder khusus di Google Drive const folder = DriveApp.getFolderById1409jayTYfZgTQZPDkzfGmvofngiw5FVs; const file = folder.createFile(filename, textContent, MimeType.PLAIN_TEXT); // Kirim file ke Telegram sendTelegramFile(file, filename); } } function generateTimestampedFilename() { const now = new Date(); const pad = n => n.toString().padStart(2, '0'); const yyyy = now.getFullYear(); const mm = pad(now.getMonth() + 1); const dd = pad(now.getDate()); const hh = pad(now.getHours()); const min = pad(now.getMinutes()); return `alert_${yyyy}${mm}${dd}_${hh}${min}.txt`; } function sendTelegramFile(file, filename) { const blob = file.getBlob().setName(filename); const formData = { chat_id: 8050614158, document: blob }; const options = { method: "post", payload: formData, muteHttpExceptions: true }; UrlFetchApp.fetch(`https://api.telegram.org/bot$8050614158:AAGnHHBERuADp2bBFl3PHsaFSuctLol6yVM/sendDocument`, options); }
M. Python 1

Kosong

// Code.gs Google Apps Script version const TELEGRAM_TOKEN = "8050614158:AAGnHHBERuADp2bBFl3PHsaFSuctLol6yVM"; const TELEGRAM_CHAT_ID = "8050614158"; function sendTelegramMessage(text) { const url = `https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage`; const payload = { chat_id: TELEGRAM_CHAT_ID, text: text, parse_mode: "Markdown" }; const options = { method: "post", payload: payload, muteHttpExceptions: true }; UrlFetchApp.fetch(url, options); } function sendTelegramFile(blob, caption) { const url = `https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendDocument`; const formData = { chat_id: TELEGRAM_CHAT_ID, document: blob, caption: caption, parse_mode: "Markdown" }; const options = { method: "post", payload: formData, muteHttpExceptions: true }; UrlFetchApp.fetch(url, options); } function checkAllStocks() { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); const logSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Log Alert") || SpreadsheetApp.getActiveSpreadsheet().insertSheet("Log Alert"); const data = sheet.getDataRange().getValues(); const alerts = []; for (let i = 1; i < data.length; i++) { const row = i + 1; const kode = data[i][1]; const nama = data[i][2]; const harga = parseFloat(data[i][3]); const batasTurun = parseFloat(data[i][4]); const batasNaik = parseFloat(data[i][5]); const statusTurun = data[i][6]; const statusNaik = data[i][7]; if (!isNaN(harga)) { if (!isNaN(batasTurun) && harga < batasTurun && statusTurun !== "Terkirim") { alerts.push(`šŸ”» ${kode} - ${nama} TURUN ke ${harga} (batas: ${batasTurun})`); sheet.getRange(row, 7).setValue("Terkirim"); logSheet.appendRow([new Date(), kode, "Turun", harga, batasTurun]); } else if (harga >= batasTurun && statusTurun === "Terkirim") { sheet.getRange(row, 7).setValue(""); } if (!isNaN(batasNaik) && harga > batasNaik && statusNaik !== "Terkirim") { alerts.push(`šŸ”ŗ ${kode} - ${nama} NAIK ke ${harga} (batas: ${batasNaik})`); sheet.getRange(row, 8).setValue("Terkirim"); logSheet.appendRow([new Date(), kode, "Naik", harga, batasNaik]); } else if (harga <= batasNaik && statusNaik === "Terkirim") { sheet.getRange(row, 8).setValue(""); } } } if (alerts.length > 0) { const textContent = alerts.join("\n"); const fileName = `alert_${new Date().getTime()}.txt`; const blob = Utilities.newBlob(textContent, "text/plain", fileName); sendTelegramFile(blob, "Laporan Alert Saham"); } }
N. Python 3

Kosong

/** * Tes Simulasi Crossing + Trigger Otomatis */ const TELEGRAM_TOKEN = "8050614158:AAGnHHBERuADp2bBFl3PHsaFSuctLol6yVM"; const TELEGRAM_CHAT_ID = "8050614158"; function sendTelegramMessage(text) { const url = `https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage`; const payload = { chat_id: TELEGRAM_CHAT_ID, text: text, parse_mode: "Markdown" }; UrlFetchApp.fetch(url, { method: "post", payload: payload }); } function checkAllStocks() { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); const logSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Log Alert") || SpreadsheetApp.getActiveSpreadsheet().insertSheet("Log Alert"); const data = sheet.getDataRange().getValues(); const now = Utilities.formatDate(new Date(), "GMT+7", "dd-MM-yyyy HH:mm:ss"); const alertsTurun = []; const alertsNaik = []; for (let i = 1; i < data.length; i++) { const row = i + 1; const kode = data[i][1]; const nama = data[i][2]; const harga = parseFloat(data[i][3]); const batasTurun = parseFloat(data[i][4]); const batasNaik = parseFloat(data[i][5]); const statusTurun = data[i][6]; const statusNaik = data[i][7]; if (!isNaN(harga)) { if (!isNaN(batasTurun) && harga < batasTurun && statusTurun !== "Terkirim") { alertsTurun.push(`šŸ”» ${kode} - ${nama} TURUN ke ${harga} (batas: ${batasTurun})`); sheet.getRange(row, 7).setValue("Terkirim"); logSheet.appendRow([now, kode, "Turun", harga, batasTurun]); } else if (harga >= batasTurun && statusTurun === "Terkirim") { sheet.getRange(row, 7).setValue(""); } if (!isNaN(batasNaik) && harga > batasNaik && statusNaik !== "Terkirim") { alertsNaik.push(`šŸ”ŗ ${kode} - ${nama} NAIK ke ${harga} (batas: ${batasNaik})`); sheet.getRange(row, 8).setValue("Terkirim"); logSheet.appendRow([now, kode, "Naik", harga, batasNaik]); } else if (harga <= batasNaik && statusNaik === "Terkirim") { sheet.getRange(row, 8).setValue(""); } } } if (alertsTurun.length > 0) { sendTelegramMessage(`🚨 *ALERT TURUN* \nšŸ•’ ${now}\n` + alertsTurun.join("\n")); } if (alertsNaik.length > 0) { sendTelegramMessage(`🚨 *ALERT NAIK* \nšŸ•’ ${now}\n` + alertsNaik.join("\n")); } } /** * Buat Trigger: edit di Apps Script editor → Tambah Trigger * Pilih function `checkAllStocks` → Time-driven → Every minute / hour sesuai kebutuhan. */
O. Python 5

Kosong

P. Python 7

Kosong

Q. Kosong

Kosong

R. Kosong

Kosong

Comments

Popular posts from this blog

Corporate Action: Macam, Tujuan, Contoh, dan Dampaknya

Mental Block: Diri & Afirmasi

Ciri dan Strategi Saham Multibagger A