Türkiye'deki halka arzlarını takip edin, kurumsal analist görüşlerini karşılaştırın ve bilinçli yatırım kararları alın.
Güncel SPK onaylı halka arzları, fiyat aralıkları ve katılım endeksi durumu.
| Sembol | Şirket | Fiyat Aralığı | Tarih | Katılım | Durum |
|---|---|---|---|---|---|
| SSAAT | S.S. Akfen Akaryakıt | 32,00 - 42,00 TL | 7 - 11 Temmuz 2025 | Uyumlu | Aktif |
| ENERY | Enerjisa Enerji | 18,50 - 24,00 TL | 14 - 18 Temmuz 2025 | Uyumlu | Aktif |
| TABGD | Tab Gıda | 88,00 - 106,00 TL | 21 - 25 Temmuz 2025 | Uygun Değil | Yakında |
| ODINE | ODİNE | 15,00 - 18,00 TL | 10 - 14 Mart 2025 | Uygun Değil | Geçmiş |
| BONYO | Bonyo Teknoloji | 24,00 - 30,00 TL | 17 - 21 Şubat 2025 | Uyumlu | Geçmiş |
| SUPRA | Supra Yatırım | -- TL | Ağustos 2025 (Tahmini) | Uyumlu | Yakında |
Kurumsal araştırma firmaları ve bağımsız analistlerin halka arz değerlendirmeleri.
Ağırlıklı değerlendirme: İzahname & Finansal Sağlık (%40) - Kurumsal Analist Görüşleri (%40) - Katılım Endeksi (%20)
Şirketin faaliyetleri Katılım Endeksi kriterlerine (faizsiz, alkol, kumar, vb.) uygun mu?
Bu kriter hard filter'dır: uyumsuzluk durumunda skor ciddi şekilde etkilenir.
Araştırma raporlarını (PDF) indiren, LLM ile duygu analizi çıkaran ve D1'e kaydeden Cloudflare Worker.
export default {
async scheduled(event, env, ctx) {
// 1. Araştırma raporlarının PDF'lerini indir
const reports = await fetchResearchReports(env);
if (reports.length === 0) return;
const db = env.SPK_DB;
const results = [];
for (const report of reports) {
// 2. PDF'den metin çıkar (simüle edilmiş - gerçekte pdf.js kullanılır)
const rawText = await extractTextFromPDF(report.pdfUrl);
// 3. LLM ile duygu analizi ve hedef fiyat çıkarımı
const analysis = await analyzeSentiment(rawText, env);
// 4. D1'e kaydet
await db.prepare(
`INSERT OR IGNORE INTO expert_analysis
(id, firm, symbol, rating, target_price, sentiment_score,
summary, report_date, pdf_link)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
).bind(
report.id,
report.firm,
analysis.symbol,
analysis.rating,
analysis.targetPrice,
analysis.sentimentScore,
analysis.summary,
report.date,
report.pdfUrl
).run();
results.push(analysis);
}
// 5. ntfy.sh ile özet bildirimi gönder
const message = results
.map((r) => `${r.firm} -> ${r.symbol}: ${r.rating}
Hedef: ${r.targetPrice} | Skor: ${r.sentimentScore}/100
${r.summary?.slice(0, 100)}`)
.join('\n\n');
await fetch(`https://ntfy.sh/${env.NTFY_TOPIC}`, {
method: 'POST',
body: message,
headers: {
'Title': 'Yeni Analist Raporu',
'Priority': 'default',
'Tags': 'bar_chart,spk',
},
});
},
async fetch(request, env) {
const url = new URL(request.url);
if (url.pathname === '/api/consensus') {
const symbol = url.searchParams.get('symbol') || '';
const db = env.SPK_DB;
const { results } = await db.prepare(
`SELECT firm, rating, target_price, sentiment_score, summary,
report_date
FROM expert_analysis
WHERE symbol = ?
ORDER BY report_date DESC
LIMIT 20`
).bind(symbol).all();
// Konsensüs hesapla
const ratings = results.map(r => r.rating);
const alCount = ratings.filter(r => r === 'AL').length;
const tutCount = ratings.filter(r => r === 'TUT').length;
const satCount = ratings.filter(r => r === 'SAT').length;
return Response.json({
reports: results,
consensus: alCount > tutCount + satCount ? 'AL'
: satCount > alCount + tutCount ? 'SAT' : 'TUT',
distribution: { AL: alCount, TUT: tutCount, SAT: satCount },
avgScore: results.length
? Math.round(results.reduce((s, r) => s + r.sentiment_score, 0) / results.length)
: 0,
});
}
if (url.pathname === '/api/setup') {
const db = env.SPK_DB;
await db.prepare(
`CREATE TABLE IF NOT EXISTS expert_analysis (
id TEXT PRIMARY KEY,
firm TEXT NOT NULL,
symbol TEXT NOT NULL,
rating TEXT NOT NULL CHECK(rating IN ('AL','TUT','SAT')),
target_price TEXT,
sentiment_score INTEGER,
summary TEXT,
report_date TEXT NOT NULL,
pdf_link TEXT,
created_at TEXT DEFAULT (datetime('now'))
)`
).run();
await db.prepare(
`CREATE INDEX IF NOT EXISTS idx_symbol
ON expert_analysis(symbol)`
).run();
return Response.json({ ok: true, message: 'Tablo hazir' });
}
return new Response('SPK Analist Monitor Worker', { status: 200 });
},
};
async function fetchResearchReports(env) {
// Simüle edilmiş - gerçekte kurumların RSS/API'lerinden çekilir
const firms = [
{ name: 'Is Yatirim', url: 'https://isyaratirim.com.tr/arastirma/raporlar' },
{ name: 'Gedik Yatirim', url: 'https://gedik.com/raporlar' },
{ name: 'Garanti BBVA', url: 'https://garantibbva.com.tr/arastirma' },
];
const reports = [];
for (const firm of firms) {
try {
const res = await fetch(firm.url, {
headers: { 'User-Agent': 'CloudflareWorker/1.0' },
});
const html = await res.text();
// PDF linklerini bul (gerçekte cheerio veya regex ile)
const pdfRegex = /<a[^>]*href="([^"]+\.pdf)"[^>]*>([^<]+halka.?arz[^<]*)<\/a>/gi;
let match;
while ((match = pdfRegex.exec(html)) !== null) {
reports.push({
id: `${firm.name.toLowerCase().replace(/\s/g, '-')}_${Date.now()}`,
firm: firm.name,
pdfUrl: match[1].startsWith('http') ? match[1]
: `https://${new URL(firm.url).host}${match[1]}`,
title: match[2].trim(),
date: new Date().toISOString().split('T')[0],
});
}
} catch (e) {
console.error(`${firm.name} fetch error:`, e);
}
}
return reports;
}
async function extractTextFromPDF(pdfUrl) {
// Gerçek uygulamada pdf.js veya Cloudflare's
// browser-rendering ile PDF parse edilir.
// Simüle edilmiş metin dönüşü:
return `Sirket gunclu piyasa kosullarinda buyume potansiyeline
sahiptir. Hedef fiyat 45.00 TL, AL onerisi. Finansal
gostergeler guclu, borcluluk orani dusuk seviyelerde.`;
}
async function analyzeSentiment(text, env) {
// Workers AI (LLM) ile duygu analizi
const symbolMatch = text.match(/([A-Z]{3,5})\s/i);
const symbol = symbolMatch ? symbolMatch[1] : 'BILINMEYEN';
const targetMatch = text.match(/hedef.?fiyat[\s:]*(\d+[.,]?\d*)/i);
const targetPrice = targetMatch ? targetMatch[1].replace('.', ',') + ' TL' : '--';
let rating = 'TUT';
let score = 50;
if (/AL\b/i.test(text)) { rating = 'AL'; score = 85; }
else if (/SAT\b/i.test(text)) { rating = 'SAT'; score = 20; }
if (/guclu|olumlu|pozitif|buyume/i.test(text)) score = Math.min(100, score + 10);
if (/zayif|olumsuz|negatif|risk/i.test(text)) score = Math.max(0, score - 15);
// Workers AI ile LLM cagrisi (opsiyonel, fallback calisir)
try {
const aiRes = await env.AI.run('@cf/meta/llama-3.1-8b-instruct', {
messages: [{
role: 'user',
content: `Su analiz metninden hisse senedi degerlendirmesini
cikar: \"\"\"${text.slice(0, 1500)}\""\". Sadece AL/TUT/SAT
ve 0-100 arasi skor dondur.`
}],
});
// AI yaniti dogrulanir; basarisiz olursa regex fallback kullanilir
if (aiRes?.response) {
const aiRating = aiRes.response.match(/\b(AL|TUT|SAT)\b/i);
const aiScore = aiRes.response.match(/\b(\d{1,3})\b/);
if (aiRating) rating = aiRating[1].toUpperCase();
if (aiScore) score = Math.min(100, Math.max(0, parseInt(aiScore[1])));
}
} catch (e) {
console.error('LLM call failed, using fallback:', e);
}
return {
symbol,
rating,
targetPrice,
sentimentScore: score,
summary: text.slice(0, 200),
firm: 'Bilinmeyen',
};
}1.Cloudflare Dashboard'da yeni bir Worker oluşturun ve kodu yapıştırın.
2.D1 veritabanı oluşturun: npx wrangler d1 create spk-analiz
3.Worker binding'leri: SPK_DB (D1), AI (Workers AI), NTFY_TOPIC (secret).
4.CRON tetikleyici: 0 8 * * 1-5 (hafta içi her sabah).