Market Scanning
Daily market scans and watchlist management.
Overview
Systematic market scanning to identify opportunities across different market conditions.
Pre-Market Scanner
Gap Up Scanner
typescript
import { StockScreener, StockField } from 'tradingview-screener';
async function preMarketGappers() {
const screener = new StockScreener();
screener
.where(StockField.CHANGE_PERCENT.gt(3))
.where(StockField.VOLUME.gte(500_000))
.where(StockField.PRICE.between(5, 100))
.select(
StockField.NAME,
StockField.PRICE,
StockField.CHANGE_PERCENT,
StockField.VOLUME
)
.sortBy(StockField.CHANGE_PERCENT, false)
.setRange(0, 20);
return await screener.get();
}
// Run before market open
const gappers = await preMarketGappers();
console.log('Pre-Market Gappers:');
console.table(gappers.data);Morning Scan
Market Leaders
Identify strong stocks at market open:
typescript
async function morningLeaders() {
const screener = new StockScreener();
screener
// Strong momentum
.where(StockField.CHANGE_PERCENT.gt(2))
.where(StockField.VOLUME.gte(1_000_000))
// Technical strength
.where(StockField.RSI.between(55, 70))
// Size and liquidity
.where(StockField.MARKET_CAPITALIZATION.gt(500e6))
.select(
StockField.NAME,
StockField.PRICE,
StockField.CHANGE_PERCENT,
StockField.RSI,
StockField.VOLUME
)
.sortBy(StockField.CHANGE_PERCENT, false);
return await screener.get();
}Midday Momentum
Continuation Patterns
typescript
async function middayMomentum() {
const screener = new StockScreener();
screener
// Sustained momentum
.where(StockField.CHANGE_PERCENT.gt(3))
// Not overextended
.where(StockField.RSI.between(60, 75))
// Liquidity
.where(StockField.VOLUME.gte(1_000_000))
.select(
StockField.NAME,
StockField.PRICE,
StockField.CHANGE_PERCENT,
StockField.RSI,
StockField.VOLUME
)
.sortBy(StockField.VOLUME, false);
return await screener.get();
}End-of-Day Review
Daily Breakouts
typescript
async function dailyBreakouts() {
const screener = new StockScreener();
screener
// Volume confirmation
.where(StockField.VOLUME.gte(1_000_000))
// Not overextended
.where(StockField.RSI.lt(75))
// Size
.where(StockField.MARKET_CAPITALIZATION.gt(1e9))
.select(
StockField.NAME,
StockField.PRICE,
StockField.CHANGE_PERCENT,
StockField.VOLUME
)
.sortBy(StockField.CHANGE_PERCENT, false);
return await screener.get();
}Sector Rotation Scanner
typescript
async function sectorRotation() {
const sectors = [
'Technology',
'Healthcare',
'Financial',
'Consumer Cyclical',
'Industrials',
'Energy',
'Utilities',
'Real Estate',
];
const sectorPerformance = [];
for (const sector of sectors) {
const screener = new StockScreener();
screener
.where(StockField.MARKET_CAPITALIZATION.gt(1e9))
.select(StockField.CHANGE_PERCENT);
const results = await screener.get();
const avgChange = results.data.reduce((sum, s) => sum + s.change_abs, 0) / results.data.length;
sectorPerformance.push({
sector,
avgChange: avgChange.toFixed(2),
count: results.totalCount,
});
}
// Sort by performance
sectorPerformance.sort((a, b) => parseFloat(b.avgChange) - parseFloat(a.avgChange));
return sectorPerformance;
}
// Usage
const sectors = await sectorRotation();
console.log('Sector Performance:');
console.table(sectors);Weekly Swing Setup
typescript
async function weeklySwingSetup() {
const screener = new StockScreener();
screener
// RSI confirmation
.where(StockField.RSI.between(40, 55))
// Quality
.where(StockField.MARKET_CAPITALIZATION.gt(2e9))
.where(StockField.VOLUME.gte(500_000))
.select(
StockField.NAME,
StockField.PRICE,
StockField.RSI,
StockField.CHANGE_PERCENT
)
.sortBy(StockField.RSI, true);
return await screener.get();
}Earnings Calendar Scanner
typescript
async function upcomingEarnings(daysAhead: number = 7) {
const screener = new StockScreener();
screener
// Size and liquidity
.where(StockField.MARKET_CAPITALIZATION.gt(1e9))
.where(StockField.VOLUME.gte(500_000))
// Technical setup
.where(StockField.RSI.between(45, 65))
.select(
StockField.NAME,
StockField.PRICE,
StockField.EARNINGS_PER_SHARE_DILUTED_TTM
)
.sortBy(StockField.PRICE, true);
const results = await screener.get();
return results.data;
}Watchlist Builder
typescript
class WatchlistManager {
private watchlists: Map<string, string[]> = new Map();
async createFromScreen(
name: string,
screener: StockScreener,
maxStocks: number = 20
): Promise<void> {
screener.setRange(0, maxStocks);
const results = await screener.get();
const symbols = results.data.map(s => s.symbol);
this.watchlists.set(name, symbols);
console.log(`Created watchlist "${name}" with ${symbols.length} stocks`);
}
async scan(name: string): Promise<any[]> {
const symbols = this.watchlists.get(name);
if (!symbols) {
throw new Error(`Watchlist "${name}" not found`);
}
const screener = new StockScreener();
screener
.select(
StockField.NAME,
StockField.PRICE,
StockField.CHANGE_PERCENT,
StockField.VOLUME,
StockField.RSI
);
const results = await screener.get();
return results.data;
}
listWatchlists(): string[] {
return Array.from(this.watchlists.keys());
}
}
// Usage
const manager = new WatchlistManager();
// Create momentum watchlist
const momentum = new StockScreener();
momentum
.where(StockField.CHANGE_PERCENT.gt(10))
.where(StockField.MARKET_CAPITALIZATION.gt(1e9));
await manager.createFromScreen('momentum', momentum, 20);
// Create value watchlist
const value = new StockScreener();
value
.where(StockField.PRICE_TO_EARNINGS_RATIO_TTM.lt(15))
.where(StockField.DIVIDEND_YIELD_FWD.gt(3));
await manager.createFromScreen('value', value, 20);
// Scan watchlists
const momentumScan = await manager.scan('momentum');
console.table(momentumScan);Multi-Strategy Scanner
typescript
async function dailyMarketScan() {
console.log('=== Daily Market Scan ===\n');
// 1. Momentum leaders
console.log('📈 Momentum Leaders:');
const momentum = await morningLeaders();
console.table(momentum.data.slice(0, 5));
// 2. Breakouts
console.log('\n🚀 New Breakouts:');
const breakouts = await dailyBreakouts();
console.table(breakouts.data.slice(0, 5));
// 3. Swing setups
console.log('\n📊 Swing Trade Setups:');
const swings = await weeklySwingSetup();
console.table(swings.data.slice(0, 5));
// 4. Sector performance
console.log('\n🏭 Sector Performance:');
const sectors = await sectorRotation();
console.table(sectors);
// 5. Oversold bounce candidates
console.log('\n💎 Oversold Stocks:');
const oversold = new StockScreener();
oversold
.where(StockField.RSI.lt(30))
.where(StockField.MARKET_CAPITALIZATION.gt(1e9))
.setRange(0, 5);
const oversoldResults = await oversold.get();
console.table(oversoldResults.data);
}
// Run daily scan
await dailyMarketScan();Automated Alert System
typescript
async function marketAlertSystem() {
const alerts = {
bigMovers: { threshold: 5, hits: [] as any[] },
volumeSurge: { threshold: 3, hits: [] as any[] },
breakouts: { hits: [] as any[] },
};
const screener = new StockScreener();
screener
.where(StockField.MARKET_CAPITALIZATION.gt(1e9))
.where(StockField.VOLUME.gte(500_000))
.select(
StockField.NAME,
StockField.PRICE,
StockField.CHANGE_PERCENT,
StockField.VOLUME
);
for await (const data of screener.stream({ interval: 60000 })) {
if (!data) continue;
alerts.bigMovers.hits = data.data.filter(
s => Math.abs(s.change_abs) >= alerts.bigMovers.threshold
);
alerts.volumeSurge.hits = data.data.filter(
s => s.volume >= alerts.volumeSurge.threshold * 1000000
);
alerts.breakouts.hits = data.data.filter(
s => s.close >= s.price * 1.05
);
if (alerts.bigMovers.hits.length > 0 ||
alerts.volumeSurge.hits.length > 0 ||
alerts.breakouts.hits.length > 0) {
console.log(`\n🚨 ALERTS ${new Date().toLocaleTimeString()}`);
if (alerts.bigMovers.hits.length > 0) {
console.log(`\n📊 Big Movers (${alerts.bigMovers.threshold}%+):`);
alerts.bigMovers.hits.forEach(s => {
console.log(` ${s.name}: ${s.change_abs > 0 ? '+' : ''}${s.change_abs}%`);
});
}
if (alerts.volumeSurge.hits.length > 0) {
console.log(`\n📈 Volume Surge (${alerts.volumeSurge.threshold}x+):`);
alerts.volumeSurge.hits.forEach(s => {
console.log(` ${s.name}: High volume`);
});
}
if (alerts.breakouts.hits.length > 0) {
console.log('\n🚀 New Highs:');
alerts.breakouts.hits.forEach(s => {
console.log(` ${s.name}: $${s.close.toFixed(2)}`);
});
}
}
}
}
// Start alert system
await marketAlertSystem();Market Summary Report
typescript
async function generateMarketSummary() {
const summary = {
timestamp: new Date().toLocaleString(),
stats: {
advancers: 0,
decliners: 0,
unchanged: 0,
newHighs: 0,
newLows: 0,
highVolume: 0,
},
};
const screener = new StockScreener();
screener
.where(StockField.MARKET_CAPITALIZATION.gt(1e9))
.select(
StockField.CHANGE_PERCENT,
StockField.PRICE,
StockField.VOLUME
);
const results = await screener.get();
results.data.forEach(stock => {
if (stock.change_abs > 0) summary.stats.advancers++;
else if (stock.change_abs < 0) summary.stats.decliners++;
else summary.stats.unchanged++;
if (stock.volume > 2000000) summary.stats.highVolume++;
});
console.log('=== Market Summary ===');
console.log(`Time: ${summary.timestamp}\n`);
console.log(`Advancers: ${summary.stats.advancers}`);
console.log(`Decliners: ${summary.stats.decliners}`);
console.log(`Advance/Decline Ratio: ${(summary.stats.advancers / summary.stats.decliners).toFixed(2)}`);
console.log(`\nHigh Volume Stocks: ${summary.stats.highVolume}`);
return summary;
}
// Generate report
await generateMarketSummary();Best Practices
- Schedule Scans: Run at consistent times daily
- Multiple Strategies: Don't rely on one scan
- Track Results: Log and review performance
- Adjust Filters: Refine based on results
- Risk Management: Always use stop losses
- Position Sizing: Don't overconcentrate
Next Steps
- Value Investing - Finding undervalued stocks
- Growth Stocks - High-growth companies
- Technical Analysis - Technical indicators