{ "name": "Olostep Investment Research HTML Email - Weekday Market Open", "nodes": [ { "parameters": { "rule": { "interval": [ { "field": "cronExpression", "expression": "30 9 * * 1-5" } ] } }, "type": "n8n-nodes-base.scheduleTrigger", "typeVersion": 1.2, "position": [ 4640, 1120 ], "name": "Weekday Market Open Trigger" }, { "parameters": {}, "type": "n8n-nodes-base.manualTrigger", "typeVersion": 1, "position": [ 4640, 1312 ], "name": "Manual Test Trigger" }, { "parameters": { "assignments": { "assignments": [ { "name": "tickers", "type": "string", "value": "MSFT,NVDA" }, { "name": "email_to", "type": "string", "value": "recipient@example.com" }, { "name": "email_from", "type": "string", "value": "sender@example.com" }, { "name": "email_subject_prefix", "type": "string", "value": "Daily Investment Research Report" } ] }, "options": {} }, "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [ 4864, 1216 ], "name": "Investment Watchlist" }, { "parameters": { "jsCode": "const data = $input.first().json;\nconst tickers = data.tickers.split(',').map(function(t) { return t.trim(); }).filter(Boolean);\n\nreturn tickers.map(function(ticker) {\n return {\n json: {\n ticker: ticker,\n investment_query: ticker + ' latest investor relations SEC filings earnings call transcript financial news risk factors catalysts',\n email_to: data.email_to,\n email_from: data.email_from,\n email_subject_prefix: data.email_subject_prefix\n }\n };\n});" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 5088, 1216 ], "name": "Split Tickers" }, { "parameters": { "operation": "search", "query": "={{ $json.investment_query }}" }, "type": "n8n-nodes-olostep.olostepScrape", "typeVersion": 1, "position": [ 5312, 1216 ], "name": "Olostep Search - Investment Sources" }, { "parameters": { "jsCode": "const items = $input.all();\n\nconst watchlist = items.map(function(item) {\n return {\n ticker: item.json.ticker || 'Unknown',\n sources: item.json.organic || item.json.results || item.json.data || []\n };\n});\n\nconst first = items.length > 0 ? items[0].json : {};\n\nreturn [\n {\n json: {\n report_date: new Date().toISOString().split('T')[0],\n watchlist: watchlist,\n email_to: first.email_to || 'recipient@example.com',\n email_from: first.email_from || 'sender@example.com',\n email_subject_prefix: first.email_subject_prefix || 'Daily Investment Research Report'\n }\n }\n];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 5536, 1216 ], "name": "Combine Ticker Research" }, { "parameters": { "modelId": { "__rl": true, "value": "gpt-5.4-mini", "mode": "list", "cachedResultName": "GPT-5.4-MINI" }, "responses": { "values": [ { "content": "=You are an investment research assistant.\n\nYou will receive search and scraped web results for multiple stock tickers. Your job is to turn the results into one clean Markdown email report for the full watchlist.\n\nImportant rules:\n- Create only one complete report for the full watchlist.\n- Do not repeat the title, generated date, executive summary, or disclaimer for each ticker.\n- Do not give direct buy, sell, or hold advice.\n- Do not say \"invest in this\" or \"sell this\".\n- Do not predict stock prices.\n- Do not invent numbers or facts.\n- Use only the information provided in the input.\n- If information is missing, write \"Not found in provided sources.\"\n- Keep the report concise but useful.\n- Group the report by ticker/company.\n- Include source links under each company.\n- For each company, include a neutral \"Signal Summary\" with: Opportunity Signals, Risk / Exit Watch Signals, and Research Priority.\n- Research Priority may be High / Medium / Low, but it must not be framed as financial advice.\n\nReport date:\n{{ $json.report_date }}\n\nInput data:\n{{ JSON.stringify($json.watchlist) }}\n\nCreate the Markdown report using this structure:\n\n# Daily Investment Research Report\n\nGenerated on: {{ $json.report_date }}\n\n## Executive Summary\n\nWrite 5-7 bullets summarizing the most important findings across all tickers.\n\n## Watchlist Signal Table\n\nCreate a simple Markdown table with these columns:\n| Ticker | Opportunity Signals | Risk / Exit Watch Signals | Research Priority |\n\nImportant: The table must not include Buy, Sell, or Hold recommendations.\n\n## Ticker-by-Ticker Analysis\n\nFor each ticker or company found in the input, create this section:\n\n### [Company Name] ([Ticker if available])\n\n#### Key Sources Reviewed\n- [Source title](Source URL)\n- [Source title](Source URL)\n\n#### Recent Updates\nSummarize the most important recent updates from the sources.\n\n#### Opportunity Signals\n- Bullet 1\n- Bullet 2\n- Bullet 3\n\n#### Risk / Exit Watch Signals\n- Bullet 1\n- Bullet 2\n- Bullet 3\n\n#### Financial / Earnings Signals\nSummarize any revenue, earnings, margin, guidance, or filing-related information found.\n\n#### Competitive Position\nSummarize any information about competitors, market position, product demand, or sector trends.\n\n#### Investor Questions to Investigate Next\n- Question 1\n- Question 2\n- Question 3\n\n#### Research Confidence\nChoose one: High / Medium / Low\n\nExplain the confidence rating in one short sentence.\n\n---\n\n## Cross-Watchlist Themes\n\nSummarize patterns across all companies, such as AI demand, data center growth, margin pressure, regulatory risk, leadership changes, earnings momentum, and competitive pressure.\n\n## Red Flags to Monitor\n\nList the most important risks found across the full watchlist.\n\n## Follow-Up Research Checklist\n\n- Review latest 10-K or 10-Q filings\n- Compare latest earnings call transcripts\n- Check revenue guidance\n- Review analyst downgrades or upgrades\n- Look for lawsuits, investigations, layoffs, or executive changes\n\n## Disclaimer\n\nThis report is generated from public web research and is for research automation only. It is not financial advice. It does not provide buy, sell, or hold recommendations.\n" } ] }, "builtInTools": {}, "options": {} }, "type": "@n8n/n8n-nodes-langchain.openAi", "typeVersion": 2.2, "position": [ 5760, 1216 ], "name": "OpenAI - Create Full Watchlist Email Report" }, { "parameters": { "jsCode": "const output = $json.output && $json.output[0] && $json.output[0].content && $json.output[0].content[0] && $json.output[0].content[0].text;\nconst markdown = output || $json.text || '';\n\nfunction escapeHtml(str) {\n return String(str)\n .replace(/&/g, '&')\n .replace(//g, '>');\n}\n\nlet html = escapeHtml(markdown);\n\nhtml = html\n .replace(/\\*\\*(.*?)\\*\\*/gim, '$1')\n .replace(/\\[(.*?)\\]\\((.*?)\\)/gim, '$1');\n\nhtml = html\n .replace(/^#### (.*$)/gim, '

$1

')\n .replace(/^### (.*$)/gim, '

$1

')\n .replace(/^## (.*$)/gim, '

$1

')\n .replace(/^# (.*$)/gim, '

$1

')\n .replace(/^---$/gim, '
');\n\nhtml = html.replace(/((?:^|\\n)\\|.+\\|\\n\\|[-:\\s|]+\\|\\n(?:\\|.+\\|\\n?)+)/g, function(tableBlock) {\n const rows = tableBlock.trim().split('\\n');\n const headers = rows[0].split('|').slice(1, -1).map(function(h) { return h.trim(); });\n const bodyRows = rows.slice(2).map(function(row) {\n return row.split('|').slice(1, -1).map(function(c) { return c.trim(); });\n });\n const thead = '' + headers.map(function(h) { return '' + h + ''; }).join('') + '';\n const tbody = '' + bodyRows.map(function(cols) {\n return '' + cols.map(function(c) { return '' + c + ''; }).join('') + '';\n }).join('') + '';\n return '' + thead + tbody + '
';\n});\n\nhtml = html.replace(/(?:^|\\n)(- .*(?:\\n- .*)*)/g, function(match) {\n const items = match\n .trim()\n .split('\\n')\n .map(function(line) { return '
  • ' + line.replace(/^- /, '') + '
  • '; })\n .join('');\n return '';\n});\n\nhtml = html\n .split('\\n')\n .map(function(line) {\n const trimmed = line.trim();\n if (!trimmed) return '';\n if (\n trimmed.startsWith('' + trimmed + '

    ';\n })\n .join('\\n');\n\nconst reportDate = new Date().toISOString().split('T')[0];\nconst subjectPrefix = $json.email_subject_prefix || 'Daily Investment Research Report';\n\nlet emailHtml = '';\nemailHtml += '';\nemailHtml += '';\nemailHtml += '
    ';\nemailHtml += '
    ';\nemailHtml += '
    ';\nemailHtml += '
    Automated Investment Research
    ';\nemailHtml += '

    Daily Investment Research Report

    ';\nemailHtml += '
    Generated on ' + reportDate + '
    ';\nemailHtml += '
    ';\nemailHtml += '
    ';\nemailHtml += 'This automated email summarizes opportunity signals, risk signals, and research priorities from public sources. It is not financial advice and does not provide buy, sell, or hold recommendations.';\nemailHtml += '
    ';\nemailHtml += '
    ' + html + '
    ';\nemailHtml += '
    ';\n\nconst styledHtml = emailHtml\n .replace(/

    /g, '

    ')\n .replace(/

    /g, '

    ')\n .replace(/

    /g, '

    ')\n .replace(/

    /g, '

    ')\n .replace(/

    /g, '

    ')\n .replace(/