Tracking trades is essential for improving any trading strategy. But manually logging every trade is time-consuming and error-prone.
In this guide, you’ll learn how to automatically log trades from TradingView alerts into Google Sheets using Google Apps Script.
This system uses TradingView webhook alerts to send JSON data directly into a Google Sheet that acts as your trading journal.
The best part: it’s completely free and requires no third-party tools like Zapier or Make.
Final Result
After completing this tutorial, your automation pipeline will look like this:
TradingView Strategy Alert
↓
Webhook
↓
Google Apps Script
↓
Google Sheets Trade Log
Each alert will automatically create a new row in your trade journal containing information such as:
- timestamp
- ticker
- trade side
- entry or exit
- price
- quantity
- strategy name
Why Use an Automated Trade Journal
Keeping a trade log allows you to:
- track strategy performance
- calculate win rate and expectancy
- review mistakes
- analyze market conditions
- improve long-term profitability
Most traders still use manual spreadsheets. By automating the process, you ensure every trade is recorded instantly and accurately.
What You Will Build
In this tutorial we will:
- Create a Google Sheets trading journal
- Build a webhook endpoint using Google Apps Script
- Send JSON alerts from TradingView
- Automatically store trade data in a spreadsheet
This works with:
- TradingView strategies
- TradingView indicators
- Pine Script alerts
- automated trading systems
Step 1 — Create a Google Sheets Trade Journal
First create a new spreadsheet in Google Sheets.
Name it something like:
Trading Journal
Create the following columns:
Received At
Event Time
Ticker
Exchange
Interval
Strategy
Action
Side
Price
Quantity
Order ID
Comment
Raw JSON
This sheet will store all alerts sent from TradingView.
Step 2 — Create the Webhook With Google Apps Script
Now we will create a small script that receives webhook alerts and writes them to the spreadsheet.
Open your spreadsheet and click:
Extensions → Apps Script
Then paste the following code.
Apps Script Webhook Code
const SHEET_NAME = 'Trade Log';
const SHARED_SECRET = 'YOUR_SHARED_SECRET';
function doPost(e) {
try {
if (!e || !e.postData || !e.postData.contents) {
return jsonResponse_({ ok: false, error: 'Empty POST body' });
}
const rawBody = e.postData.contents;
const data = JSON.parse(rawBody);
// Basic auth via shared secret
if (data.secret !== SHARED_SECRET) {
return jsonResponse_({ ok: false, error: 'Unauthorized' });
}
const trade = normalizePayload_(data);
appendTrade_(trade, rawBody);
return jsonResponse_({ ok: true, message: 'Trade logged' });
} catch (err) {
return jsonResponse_({
ok: false,
error: err.message || String(err)
});
}
}
function normalizePayload_(data) {
const now = new Date();
return {
receivedAt: now,
eventTime: data.timestamp || '',
ticker: data.ticker || '',
exchange: data.exchange || '',
interval: data.interval || '',
strategy: data.strategy || '',
action: data.action || '',
side: data.side || '',
price: toNumber_(data.price),
qty: toNumber_(data.qty),
orderId: data.order_id || '',
comment: data.comment || ''
};
}
function appendTrade_(trade, rawBody) {
const sheet = getSheet_();
ensureHeaders_(sheet);
sheet.appendRow([
trade.receivedAt,
trade.eventTime,
trade.ticker,
trade.exchange,
trade.interval,
trade.strategy,
trade.action,
trade.side,
trade.price,
trade.qty,
trade.orderId,
trade.comment,
rawBody
]);
}
function getSheet_() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
let sheet = ss.getSheetByName(SHEET_NAME);
if (!sheet) {
sheet = ss.insertSheet(SHEET_NAME);
}
return sheet;
}
function ensureHeaders_(sheet) {
if (sheet.getLastRow() > 0) return;
sheet.appendRow([
'Received At',
'Event Time',
'Ticker',
'Exchange',
'Interval',
'Strategy',
'Action',
'Side',
'Price',
'Qty',
'Order ID',
'Comment',
'Raw JSON'
]);
}
function toNumber_(value) {
const n = Number(value);
return Number.isFinite(n) ? n : '';
}
function jsonResponse_(obj) {
return ContentService
.createTextOutput(JSON.stringify(obj))
.setMimeType(ContentService.MimeType.JSON);
}
Step 3 — Deploy the Script as a Web App
Next we need to expose the script as a webhook endpoint.
Click:
Deploy → New Deployment
Choose:
Type: Web App
Then set the following options:
Execute as: Me
Who has access: Anyone
After deployment you will receive a web app URL.
This URL is your webhook endpoint.
Step 4 — Example JSON Alert Payload
TradingView will send alerts as JSON to the webhook.
Example payload:
{
"secret": "YOUR_SHARED_SECRET",
"timestamp": "2026-03-14T12:30:00Z",
"ticker": "BTCUSDT",
"exchange": "BINANCE",
"interval": "5",
"strategy": "EMA Pullback v1",
"action": "entry",
"side": "long",
"price": 68421.5,
"qty": 0.1,
"order_id": "TEST_001",
"comment": "Manual webhook test"
}
Each alert will create a new row in the spreadsheet.
Step 5 — Create a TradingView Alert
Open your chart in TradingView and create an alert.
Configure the alert with:
Webhook URL:
YOUR_APPS_SCRIPT_WEBHOOK
Alert message:
{{strategy.order.alert_message}}
This allows TradingView to send custom JSON defined inside your Pine Script strategy.
Step 6 — Example Pine Script Strategy
Below is a minimal strategy that sends JSON alerts.
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © QuantNomad
//@version=6
//@strategy_alert_message {{strategy.order.alert_message}}
strategy("Webhook JSON Test Strategy", overlay=true, initial_capital=10000)
// === Inputs ===
secret = input.string("YOUR_SHARED_SECRET", "Webhook Secret")
qty = input.float(1, "Qty", minval=0.0)
// === Simple demo logic ===
// Enter long when fast EMA crosses above slow EMA
// Exit when fast EMA crosses below slow EMA
fastEMA = ta.ema(close, 9)
longEntry = ta.crossover(close, fastEMA)
longExit = ta.crossunder(close, fastEMA)
// Optional plots
plot(fastEMA, "Fast EMA")
// Build JSON manually
entryJson = '{"secret":"' + secret + '",' +
'"timestamp":"' + str.tostring(time) + '",' +
'"ticker":"' + syminfo.ticker + '",' +
'"exchange":"' + syminfo.prefix + '",' +
'"interval":"' + timeframe.period + '",' +
'"strategy":"Webhook JSON Test Strategy",' +
'"action":"entry",' +
'"side":"long",' +
'"price":' + str.tostring(close) + ',' +
'"qty":' + str.tostring(qty) + ',' +
'"order_id":"LONG_ENTRY",' +
'"comment":"EMA crossover entry"}'
exitJson = '{"secret":"' + secret + '",' +
'"timestamp":"' + str.tostring(time) + '",' +
'"ticker":"' + syminfo.ticker + '",' +
'"exchange":"' + syminfo.prefix + '",' +
'"interval":"' + timeframe.period + '",' +
'"strategy":"Webhook JSON Test Strategy",' +
'"action":"exit",' +
'"side":"long",' +
'"price":' + str.tostring(close) + ',' +
'"qty":' + str.tostring(qty) + ',' +
'"order_id":"LONG_ENTRY",' +
'"comment":"EMA crossunder exit"}'
// Orders
if longEntry
strategy.entry("Long", strategy.long, qty=qty, alert_message=entryJson)
if longExit
strategy.close("Long", alert_message=exitJson)
Improvements You Can Add
This basic system can easily be expanded.
Ideas include:
- automatic PnL calculations
- open vs closed trades
- performance dashboards
- strategy analytics
- Telegram notifications
- email alerts
- trade statistics
With a few additional scripts you can turn this into a full automated trading journal.
Conclusion
In this tutorial we built a fully automated trading journal using TradingView alerts and Google Sheets.
The system:
- receives webhook alerts
- processes JSON data
- stores trades automatically
Because it uses Google Apps Script, it runs entirely in the cloud and requires no external servers or paid integrations.



