Saham Batas Turun & Naik Bot Telegram Spreadsheet
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.
-
Buka Google Sheets:
- Kunjungi docs.google.com/spreadsheets.
- Buka spreadsheet yang ingin kamu gunakan.
-
Buka Editor Apps Script:
- Klik menu Extensions (Ekstensi).
- Pilih Apps Script.
-
Tempel atau tulis kode program:
- Hapus kode default (jika ada), lalu tempel kode baru yang kamu inginkan.
-
Simpan proyek:
- Klik ikon disket š¾ atau tekan Ctrl + S.
- Pastikan tidak ada error dalam kode.
- Ubah nama proyek di kiri atas, misalnya: Script Otomatisasi.
-
Jalankan fungsi dari kode:
- Klik tombol Run (ikon ▶️).
- Pilih nama fungsi yang ingin dijalankan (jika ada lebih dari satu).
-
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).
-
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
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
-
Buka Apps Script Editor
Di Google Sheets, klik:Extensions → Apps Script
-
Klik Ikon Triggers
Di sebelah kiri, klik ikon ⏰ (jam alarm) → akan terbuka halaman "Triggers". -
Klik
+ Add Trigger
Tombol ini berada di kanan bawah layar. -
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 memilihTime-driven
, pilih frekuensi: tiap menit, jam, hari, minggu, dll. - Failure notification settings:
Pilih apakah ingin mendapat email notifikasi jika terjadi error.
- Choose which function to run: Pilih fungsi yang ingin dijalankan, misalnya:
-
Klik Save
KlikSave
→ 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.
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.
Siapkan Bot Telegram
- Buka aplikasi Telegram di perangkat Anda.
- Cari akun resmi (biru centang) @BotFather.
- Ketik perintah
/newbot
untuk membuat bot baru. - Ikuti instruksi untuk memberi nama dan username.bot.
- Panjang contoh token 47 karakter, catat Token API yang diberikan. Token ini diperlukan untuk menghubungkan bot dengan aplikasi Anda.
- Buka di browser, https://api.telegram.org/bot[YOUR_TOKEN]/getUpdatesberhasil jika: {"ok":true,"result":[]}
- 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}}
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); }⚙️ 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:
- Ketika harga melewati batas, script akan:
- Mengirim alert ke Telegram.
- Menandai kolom Status dengan nilai "Naik" atau "Turun".
- Pada eksekusi berikutnya (misalnya 10 menit kemudian), script akan melewati saham yang statusnya sudah "Naik" atau "Turun" sehingga tidak mengirim alert ulang.
- 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); }š 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); }✅ 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); }šÆ 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
-
Di Telegram:
Kamu akan menerima file.txt
dengan nama seperti:
dengan isi file misalnya:alert_20250713_1659.txt
š» GOTO TURUN ke 74 (batas: 80) šŗ BBCA NAIK ke 9500 (batas: 9400)
-
Di Google Drive:
File yang sama akan otomatis disimpan di folder Google Drive kamu. -
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()); }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); }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"); } }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. */Kosong
Kosong
Kosong
Kosong
Comments
Post a Comment