Real-world examples to help you get started quickly
Create alerts for multiple stocks in your portfolio with different thresholds.
// Portfolio monitoring example
const portfolio = [
{ symbol: 'AAPL', buyPrice: 150, stopLoss: 0.1, takeProfit: 0.2 },
{ symbol: 'GOOGL', buyPrice: 2800, stopLoss: 0.1, takeProfit: 0.25 },
{ symbol: 'MSFT', buyPrice: 300, stopLoss: 0.08, takeProfit: 0.15 }
];
async function setupPortfolioAlerts(portfolio) {
const alerts = [];
for (const stock of portfolio) {
// Stop loss alert
const stopLossAlert = await createAlert({
symbol: stock.symbol,
condition: 'price_below',
threshold: stock.buyPrice * (1 - stock.stopLoss),
notification: 'sms' // Urgent alerts via SMS
});
// Take profit alert
const takeProfitAlert = await createAlert({
symbol: stock.symbol,
condition: 'price_above',
threshold: stock.buyPrice * (1 + stock.takeProfit),
notification: 'email'
});
alerts.push({
stock: stock.symbol,
stopLoss: stopLossAlert,
takeProfit: takeProfitAlert
});
}
return alerts;
}
// Usage
const portfolioAlerts = await setupPortfolioAlerts(portfolio);
console.log('Portfolio alerts created:', portfolioAlerts);
# Portfolio monitoring example
portfolio = [
{'symbol': 'AAPL', 'buy_price': 150, 'stop_loss': 0.1, 'take_profit': 0.2},
{'symbol': 'GOOGL', 'buy_price': 2800, 'stop_loss': 0.1, 'take_profit': 0.25},
{'symbol': 'MSFT', 'buy_price': 300, 'stop_loss': 0.08, 'take_profit': 0.15}
]
def setup_portfolio_alerts(portfolio):
alerts = []
for stock in portfolio:
# Stop loss alert
stop_loss_alert = client.alerts.create(
symbol=stock['symbol'],
condition='price_below',
threshold=stock['buy_price'] * (1 - stock['stop_loss']),
notification='sms' # Urgent alerts via SMS
)
# Take profit alert
take_profit_alert = client.alerts.create(
symbol=stock['symbol'],
condition='price_above',
threshold=stock['buy_price'] * (1 + stock['take_profit']),
notification='email'
)
alerts.append({
'stock': stock['symbol'],
'stop_loss': stop_loss_alert,
'take_profit': take_profit_alert
})
return alerts
# Usage
portfolio_alerts = setup_portfolio_alerts(portfolio)
print(f'Portfolio alerts created: {len(portfolio_alerts) * 2} alerts')
Set up alerts based on technical indicators like moving averages and RSI.
// Technical indicator alerts
async function setupTechnicalAlerts(symbol) {
const alerts = [];
// Golden Cross alert (bullish signal)
alerts.push(await createAlert({
symbol: symbol,
condition: 'ma_crossover_golden',
notification: 'email'
}));
// Death Cross alert (bearish signal)
alerts.push(await createAlert({
symbol: symbol,
condition: 'ma_crossover_death',
notification: 'email'
}));
// RSI Oversold (< 30)
alerts.push(await createAlert({
symbol: symbol,
condition: 'rsi_limit',
threshold: 30,
parameters: {
direction: 'below',
period: 14
},
notification: 'email'
}));
// RSI Overbought (> 70)
alerts.push(await createAlert({
symbol: symbol,
condition: 'rsi_limit',
threshold: 70,
parameters: {
direction: 'above',
period: 14
},
notification: 'email'
}));
// Volume spike (50% above 10-day average)
alerts.push(await createAlert({
symbol: symbol,
condition: 'volume_change',
threshold: 150,
parameters: {
period: 10
},
notification: 'email'
}));
return alerts;
}
// Monitor multiple stocks
const techStocks = ['AAPL', 'GOOGL', 'MSFT', 'NVDA', 'TSLA'];
for (const stock of techStocks) {
await setupTechnicalAlerts(stock);
}
Track important corporate events and fundamental changes.
// Track earnings and dividends
async function setupFundamentalAlerts(symbol, options = {}) {
const alerts = [];
// Earnings announcement reminder
if (options.trackEarnings) {
alerts.push(await createAlert({
symbol: symbol,
condition: 'earnings_announcement',
parameters: {
days_before: 1 // Alert 1 day before earnings
},
notification: 'email'
}));
}
// Dividend tracking
if (options.trackDividends) {
// Ex-dividend date alert
alerts.push(await createAlert({
symbol: symbol,
condition: 'dividend_ex_date',
parameters: {
days_before: 2 // Alert 2 days before ex-dividend
},
notification: 'email'
}));
// Payment date alert
alerts.push(await createAlert({
symbol: symbol,
condition: 'dividend_payment',
parameters: {
shares_owned: options.shares || 100
},
notification: 'email'
}));
}
// P/E ratio monitoring
if (options.targetPE) {
alerts.push(await createAlert({
symbol: symbol,
condition: 'pe_ratio_below',
threshold: options.targetPE,
notification: 'email'
}));
}
return alerts;
}
// Example usage
const fundamentalAlerts = await setupFundamentalAlerts('AAPL', {
trackEarnings: true,
trackDividends: true,
shares: 100,
targetPE: 25
});
Send alert notifications to a Discord channel using webhooks.
// Express.js webhook endpoint for Discord integration
const express = require('express');
const crypto = require('crypto');
const axios = require('axios');
const app = express();
app.use(express.raw({ type: 'application/json' }));
const WEBHOOK_SECRET = process.env.STOCKALERT_WEBHOOK_SECRET;
const DISCORD_WEBHOOK_URL = process.env.DISCORD_WEBHOOK_URL;
// Verify webhook signature
function verifySignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return signature === 'sha256=' + expected;
}
// Format alert for Discord
function formatDiscordMessage(alert) {
const color = alert.condition.includes('above') ? 0x00ff00 : 0xff0000;
return {
embeds: [{
title: `🚨 ${alert.company_name} (${alert.symbol})`,
description: `Alert triggered: ${alert.condition}`,
color: color,
fields: [
{
name: 'Target Value',
value: `$${alert.threshold}`,
inline: true
},
{
name: 'Current Price',
value: `$${alert.triggered_value}`,
inline: true
},
{
name: 'Change',
value: `${((alert.triggered_value - alert.threshold) / alert.threshold * 100).toFixed(2)}%`,
inline: true
}
],
timestamp: new Date().toISOString()
}]
};
}
app.post('/webhook/stockalert', async (req, res) => {
const signature = req.headers['x-stockalert-signature'];
const event = req.headers['x-stockalert-event'];
// Verify signature
if (!verifySignature(req.body, signature, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const data = JSON.parse(req.body);
// Handle different event types
switch (event) {
case 'alert.triggered':
try {
// Send to Discord
await axios.post(DISCORD_WEBHOOK_URL,
formatDiscordMessage(data.data.alert)
);
console.log('Alert sent to Discord');
} catch (error) {
console.error('Discord webhook error:', error);
}
break;
// Handle other events...
}
res.status(200).send('OK');
});
app.listen(3000, () => {
console.log('Webhook server running on port 3000');
});
Log all alert events to a database for analysis and backtesting.
// PostgreSQL integration example
const { Pool } = require('pg');
const pool = new Pool({
connectionString: process.env.DATABASE_URL
});
// Create alerts table
async function setupDatabase() {
await pool.query(`
CREATE TABLE IF NOT EXISTS alert_events (
id SERIAL PRIMARY KEY,
event_id VARCHAR(50) UNIQUE,
event_type VARCHAR(50),
alert_id UUID,
stock_symbol VARCHAR(10),
alert_type VARCHAR(50),
target_value DECIMAL(10, 2),
triggered_value DECIMAL(10, 2),
triggered_at TIMESTAMP,
raw_data JSONB,
created_at TIMESTAMP DEFAULT NOW()
)
`);
}
// Webhook handler with database logging
app.post('/webhook/stockalert', async (req, res) => {
const signature = req.headers['x-stockalert-signature'];
const event = req.headers['x-stockalert-event'];
if (!verifySignature(req.body, signature, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const data = JSON.parse(req.body);
try {
// Log to database
await pool.query(`
INSERT INTO alert_events (
event_id, event_type, alert_id, stock_symbol,
alert_type, target_value, triggered_value,
triggered_at, raw_data
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
ON CONFLICT (event_id) DO NOTHING
`, [
data.id,
event,
data.data.alert.id,
data.data.alert.symbol,
data.data.alert.condition,
data.data.alert.threshold,
data.data.alert.triggered_value,
data.data.alert.triggered_at,
data
]);
// Process based on event type
if (event === 'alert.triggered') {
await processTriggeredAlert(data.data.alert);
}
} catch (error) {
console.error('Database error:', error);
return res.status(500).send('Internal error');
}
res.status(200).send('OK');
});
Efficiently manage large numbers of alerts with batch operations.
// Batch alert manager
class AlertBatchManager {
constructor(apiKey, options = {}) {
this.apiKey = apiKey;
this.batchSize = options.batchSize || 10;
this.concurrency = options.concurrency || 3;
this.retryAttempts = options.retryAttempts || 3;
}
// Create multiple alerts with rate limiting
async createBatch(alerts) {
const results = [];
const errors = [];
// Process in batches
for (let i = 0; i < alerts.length; i += this.batchSize) {
const batch = alerts.slice(i, i + this.batchSize);
// Process batch with concurrency limit
const batchResults = await Promise.allSettled(
batch.map(alert => this.createWithRetry(alert))
);
// Collect results
batchResults.forEach((result, index) => {
if (result.status === 'fulfilled') {
results.push(result.value);
} else {
errors.push({
alert: batch[index],
error: result.reason
});
}
});
// Rate limit between batches
if (i + this.batchSize < alerts.length) {
await this.sleep(1000); // 1 second between batches
}
}
return { results, errors };
}
async createWithRetry(alert, attempt = 1) {
try {
const response = await fetch('https://stockalert.pro/api/public/v1/alerts', {
method: 'POST',
headers: {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify(alert)
});
if (response.status === 429 && attempt < this.retryAttempts) {
const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
await this.sleep(retryAfter * 1000);
return this.createWithRetry(alert, attempt + 1);
}
if (!response.ok) {
throw new Error(`Failed to create alert: ${response.statusText}`);
}
return await response.json();
} catch (error) {
if (attempt < this.retryAttempts) {
await this.sleep(Math.pow(2, attempt) * 1000); // Exponential backoff
return this.createWithRetry(alert, attempt + 1);
}
throw error;
}
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
// Usage
const batchManager = new AlertBatchManager('sk_your_api_key');
// Create 100 alerts efficiently
const alerts = generateAlerts(100); // Your alert generation logic
const { results, errors } = await batchManager.createBatch(alerts);
console.log(`Created ${results.length} alerts successfully`);
console.log(`Failed to create ${errors.length} alerts`);
Keep alerts synchronized between your application and StockAlert.pro.
// Alert synchronization service
class AlertSyncService {
constructor(apiClient, localDb) {
this.api = apiClient;
this.db = localDb;
}
async syncAlerts() {
console.log('Starting alert synchronization...');
// Fetch all remote alerts
const remoteAlerts = await this.fetchAllAlerts();
const localAlerts = await this.db.getAllAlerts();
// Create maps for efficient lookup
const remoteMap = new Map(remoteAlerts.map(a => [a.id, a]));
const localMap = new Map(localAlerts.map(a => [a.remote_id, a]));
const operations = {
create: [],
update: [],
delete: []
};
// Find alerts to create locally
for (const [id, remote] of remoteMap) {
if (!localMap.has(id)) {
operations.create.push(remote);
} else {
const local = localMap.get(id);
if (this.needsUpdate(local, remote)) {
operations.update.push({ local, remote });
}
}
}
// Find alerts to delete locally
for (const [remoteId, local] of localMap) {
if (!remoteMap.has(remoteId)) {
operations.delete.push(local);
}
}
// Execute operations
await this.executeSync(operations);
console.log('Synchronization complete:', {
created: operations.create.length,
updated: operations.update.length,
deleted: operations.delete.length
});
}
async fetchAllAlerts() {
const alerts = [];
let page = 1;
let hasMore = true;
while (hasMore) {
const response = await this.api.alerts.list({
page,
limit: 100
});
alerts.push(...response.data);
hasMore = response.totalPages > page;
page++;
}
return alerts;
}
needsUpdate(local, remote) {
return local.is_active !== remote.is_active ||
local.threshold !== remote.threshold ||
local.updated_at < remote.updated_at;
}
async executeSync(operations) {
// Create new alerts
for (const alert of operations.create) {
await this.db.createAlert({
remote_id: alert.id,
...alert
});
}
// Update existing alerts
for (const { local, remote } of operations.update) {
await this.db.updateAlert(local.id, {
is_active: remote.is_active,
threshold: remote.threshold,
updated_at: remote.updated_at
});
}
// Delete removed alerts
for (const alert of operations.delete) {
await this.db.deleteAlert(alert.id);
}
}
}
// Run sync periodically
const syncService = new AlertSyncService(apiClient, database);
setInterval(() => syncService.syncAlerts(), 5 * 60 * 1000); // Every 5 minutes