5. Part: App Script Bot-1 Telegram Saham Turun
/****************************************************
* RESET STATUS TURUN & NAIK SETIAP PAGI (Sheet1)
****************************************************/
function resetStatus() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
const lastRow = sheet.getLastRow();
// Kolom J & K → Status Turun & Status Naik
sheet.getRange(2, 10, lastRow - 1, 2).clearContent();
Logger.log("Status Turun & Status Naik telah direset.");
}
/****************************************************
* PASANG SEMUA TRIGGER OTOMATIS SEKALI KLIK
****************************************************/
function createTriggers() {
// Hapus semua trigger lama dulu biar bersih
deleteAllTriggers();
// Update harga tiap 1 menit
ScriptApp.newTrigger("updateHarga")
.timeBased()
.everyMinutes(1)
.create();
// Cek alert tiap 1 menit
ScriptApp.newTrigger("checkStockAlerts")
.timeBased()
.everyMinutes(1)
.create();
// Reset status sekali sehari jam 06:00
ScriptApp.newTrigger("resetStatus")
.timeBased()
.atHour(6)
.everyDays(1)
.create();
Logger.log("Semua trigger berhasil dipasang!");
}
/****************************************************
* HAPUS SEMUA TRIGGER (AMAN)
****************************************************/
function deleteAllTriggers() {
const triggers = ScriptApp.getProjectTriggers();
triggers.forEach(trigger => {
ScriptApp.deleteTrigger(trigger);
});
Logger.log("Semua trigger lama telah dihapus.");
}
/****************************************************
* RESET STATUS SETIAP PAGI
****************************************************/
function resetStatus() {
const sheet = SpreadsheetApp.getActive().getSheetByName("Sheet1");
const lastRow = sheet.getLastRow();
sheet.getRange(2, 10, lastRow - 1, 2).clearContent();
Logger.log("Status Turun & Status Naik telah direset.");
}
/****************************************************
* TRIGGER OTOMATIS — INSTAL SEMUA SEKALI (saja) KLIK
****************************************************/
function createTriggers() {
deleteAllTriggers();
ScriptApp.newTrigger("updateHarga")
.timeBased()
.everyMinutes(1)
.create();
ScriptApp.newTrigger("checkStockAlerts")
.timeBased()
.everyMinutes(1)
.create();
ScriptApp.newTrigger("resetStatus")
.timeBased()
.atHour(6)
.everyDays(1)
.create();
Logger.log("Semua trigger berhasil dipasang.");
}
/****************************************************
* HAPUS SEMUA TRIGGER - Wajib sebelum memasang trigger baru.
****************************************************/
function deleteAllTriggers() {
const triggers = ScriptApp.getProjectTriggers();
triggers.forEach(t => ScriptApp.deleteTrigger(t));
Logger.log("Semua trigger lama telah dihapus.");
}
/****************************************************
* Skip otomatis jika hari libur (pakai Google Calendar) - BB1?
scheduler.gs
⭐ Auto ON jam 08:55
⭐ Auto OFF jam 16:15
⭐ Hanya Senin–Jumat
****************************************************/
function autoOnOffController() {
const now = new Date();
const day = now.getDay(); // 1=Senin … 5=Jumat
// Skip Sabtu Minggu
if (day === 0 || day === 6) {
SYSTEM_STATUS = false;
return;
}
// Cek libur nasional (opsional)
if (isHariLibur()) {
SYSTEM_STATUS = false;
return;
}
const hh = now.getHours().toString().padStart(2,"0");
const mm = now.getMinutes().toString().padStart(2,"0");
const currentTime = `${hh}:${mm}`;
if (currentTime === MARKET_OPEN) {
SYSTEM_STATUS = true;
notifyAll("📈 *Bursa Dibuka*\nSistem otomatis *ON*");
}
if (currentTime === MARKET_CLOSE) {
SYSTEM_STATUS = false;
notifyAll("📉 *Bursa Ditutup*\nSistem otomatis *OFF*");
}
}
/****************************************************
* calendar.gs — Skip hari libur nasional (opsional) - BB2?
****************************************************/
function isHariLibur() {
const cal = CalendarApp.getCalendarById("id.indonesian#holiday@group.v.calendar.google.com");
const now = new Date();
const events = cal.getEventsForDay(now);
return events.length > 0; // ada libur
}
/****************************************************
* main.gs – Hemat kuota, Cache Harga, Mini Sparkline
⭐ Harga hemat kuota (tidak memanggil semua tiap menit)
GoogleFinance hanya di-refresh 1 menit sekali, tetapi row yang tidak berubah tidak di-tulis ulang.
****************************************************/
function updateHarga() {
if (!SYSTEM_STATUS) return;
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName(SHEET_NAME);
const tickers = sh.getRange("B2:B").getValues().flat().filter(String);
tickers.forEach((kode, i) => {
const row = i + 2;
const formula = `=GOOGLEFINANCE("${kode}","price")`;
const existing = sh.getRange(row, 3).getFormula();
if (existing !== formula) {
sh.getRange(row, 3).setFormula(formula);
}
});
}
/****************************************************
* Mini Grafik (Sparkline) tiap baris
****************************************************/
function updateSparkline() {
if (!SYSTEM_STATUS) return;
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName(SHEET_NAME);
const lastCol = sh.getLastColumn();
const tickers = sh.getRange("B2:B").getValues().flat().filter(String);
tickers.forEach((kode, i) => {
const row = i + 2;
const spark = `=SPARKLINE(F${row}:Z${row}, {"charttype","line";"color","red"})`;
sh.getRange(row, lastCol).setFormula(spark);
});
}
/****************************************************
* checkStockAlerts() – alert naik/turun + Broadcast multi-user - AA1?
****************************************************/
function checkStockAlerts() {
if (!SYSTEM_STATUS) return;
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName(SHEET_NAME);
const tickers = sh.getRange("B2:B").getValues().flat().filter(String);
tickers.forEach((kode, i) => {
const row = i + 2;
const harga = sh.getRange(row, 3).getValue();
const alertHigh = sh.getRange(row, 4).getValue();
const alertLow = sh.getRange(row, 5).getValue();
if (harga >= alertHigh && alertHigh) {
notifyAll(`🚀 *${kode} naik!* Harga: ${harga}`);
}
if (harga <= alertLow && alertLow) {
notifyAll(`📉 *${kode} turun!* Harga: ${harga}`);
}
});
}
/****************************************************
* telegram.gs — Multi-user Broadcast - AA2?
****************************************************/
function notifyAll(text) {
TELEGRAM_USERS.forEach(id => sendTelegram(id, text));
}
function sendTelegram(chatId, text) {
const url = `https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage`;
const payload = {
chat_id: chatId,
text: text,
parse_mode: "Markdown"
};
UrlFetchApp.fetch(url, {
method: "post",
contentType: "application/json",
payload: JSON.stringify(payload)
});
}
/****************************************************
* Broadcast dengan Mini Grafik Sparkline (emoji) - AA3?
Ini contoh sesuai permintaan Anda untuk grafik mini di Telegram
(karena Telegram tidak bisa SPARKLINE, jadi kita buat visual ASCII/emoji).
Contoh grafik naik-turun (max 10 titik):
****************************************************/
function notifySparkline(symbol, pricesArray) {
// pilih 10 titik terakhir
const prices = pricesArray.slice(-10);
const max = Math.max(...prices);
const min = Math.min(...prices);
// buat grafik mini
const bars = prices.map(p => {
const ratio = (p - min) / (max - min + 0.0001);
const height = Math.round(ratio * 7); // 7 level grafik
const levels = ["▁","▂","▃","▄","▅","▆","▇","█"];
return levels[height];
}).join("");
const message =
`📊 *${symbol} Mini Chart*\n` +
`\`${bars}\`\n` +
`High: ${max}\nLow: ${min}`;
TELEGRAM_USERS.forEach(id => sendTelegram(id, message));
}
/****************************************************
* sendTelegram() versi paling stabil
Tinggal dipake di bawah semua fungsi di atas:
****************************************************/
function sendTelegram(chatId, text) {
const url = `https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage`;
const payload = {
chat_id: chatId,
text: text,
parse_mode: "Markdown"
};
UrlFetchApp.fetch(url, {
method: "post",
contentType: "application/json",
payload: JSON.stringify(payload)
});
}
Comments
Post a Comment