Apps Script — paste this into Extensions → Apps Script, then redeploy
function doGet() {
var sheet = SpreadsheetApp
.getActiveSpreadsheet()
.getSheetByName("Log");
var values = sheet.getDataRange().getValues();
var tz = Session.getScriptTimeZone();
// Find header row (col A = "date")
var hdr = -1;
for (var i = 0; i < values.length; i++) {
if (String(values[i][0]).toLowerCase().trim() === "date") {
hdr = i; break;
}
}
if (hdr < 0) {
return ContentService
.createTextOutput(JSON.stringify({error:"Header row not found"}))
.setMimeType(ContentService.MimeType.JSON);
}
// Map by column position: A=date B=bank C=pepperstone
// D=ext_flow E=note F=total G=pnl H=sub_ret I=twr J=hwm K=dd$ L=dd%
var rows = [];
for (var r = hdr + 1; r < values.length; r++) {
var row = values[r];
var bank = row[1];
if (bank === "" || bank === null || bank === undefined) continue;
var bankNum = (typeof bank === "number") ? bank
: parseFloat(String(bank).replace(/[$,]/g, ""));
if (isNaN(bankNum)) continue;
var d = row[0];
var dateStr = (d instanceof Date)
? Utilities.formatDate(d, tz, "yyyy-MM-dd")
: String(d || "").slice(0, 10);
rows.push({
date: dateStr,
bank: bankNum,
pepperstone: parseNum(row[2]),
external_flow: parseNum(row[3]),
note: String(row[4] || ""),
total_equity: parseNum(row[5]),
trading_pnl: parseNum(row[6]),
cumulative_twr: parseNum(row[8]),
high_watermark: parseNum(row[9]),
drawdown_usd: parseNum(row[10]),
drawdown_pct: parseNum(row[11])
});
}
return ContentService
.createTextOutput(JSON.stringify(rows))
.setMimeType(ContentService.MimeType.JSON);
}
function parseNum(v) {
if (v === "" || v === null || v === undefined) return null;
if (typeof v === "number") return isNaN(v) ? null : v;
var s = String(v).replace(/[$,%\s]/g, "").replace(/,/g, "");
if (s.charAt(0) === "(" && s.slice(-1) === ")") {
return -parseFloat(s.slice(1, -1));
}
var n = parseFloat(s);
return isNaN(n) ? null : n;
}
After pasting: Deploy → Manage deployments → Edit (pencil) → Version: New version → Deploy. URL stays the same.