-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild_static.py
More file actions
1708 lines (1586 loc) · 92.7 KB
/
Copy pathbuild_static.py
File metadata and controls
1708 lines (1586 loc) · 92.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env python3
"""
DataSignals Lab - static site generator.
Produces a fully static, buildless `public/` folder (pure HTML/CSS/JS + assets)
that can be drag-and-dropped into Netlify, or deployed with no build command.
Content comes from the existing Jekyll markdown (front-matter + body), the same
texts that are live on Apify and GitHub, wrapped in a premium template.
Run: python3 build_static.py
"""
import os, re, glob, shutil, datetime, html as htmllib
import markdown
ROOT = os.path.dirname(os.path.abspath(__file__))
OUT = os.path.join(ROOT, "public")
BASE = "https://datasignalslab.com"
# Apify affiliate referral id (FirstPromoter). Appended to every click-through
# apify.com link via add_referral() in render_page(); SEO/identity refs
# (JSON-LD "url"/sameAs, canonical) stay clean because they use no href=.
REFERRAL = "wnlxst"
APIFY_PROFILE = "https://apify.com/datasignalslab"
GITHUB_PROFILE = "https://github.com/datasignalslab"
# Sitemap-lastmod volgt de bouwdatum automatisch.
BUILD_DATE = __import__("datetime").date.today().isoformat()
def add_referral(html):
"""Append ?fpr=<REFERRAL> to every href pointing at apify.com (exact host).
Leaves mcp.apify.com and other subdomains, JSON-LD and canonical untouched."""
def repl(m):
url = m.group(1)
if "fpr=" in url:
return m.group(0)
frag = ""
if "#" in url:
url, frag = url.split("#", 1)
frag = "#" + frag
sep = "&" if "?" in url else "?"
return f'href="{url}{sep}fpr={REFERRAL}{frag}"'
return re.sub(r'href="(https://apify\.com[^"]*)"', repl, html)
def add_referral_text(text):
"""Same as add_referral but for bare apify.com URLs in plain-text/markdown
(llms.txt / llms-full.txt). Skips mcp.apify.com and already-tagged URLs."""
def repl(m):
url = m.group(0)
if "fpr=" in url:
return url
sep = "&" if "?" in url else "?"
return f"{url}{sep}fpr={REFERRAL}"
return re.sub(r'https://apify\.com[^\s)\]>"]*', repl, text)
# ---------------------------------------------------------------------------
# Product / page metadata (improved short copy for the homepage grid)
# ---------------------------------------------------------------------------
PRODUCTS = [
# html, icon, short title, blurb, category
("sec-form4-insider-buying.html", "icon-sec-form4.png", "Insider Buying Clusters", "When several insiders buy the same stock within days - scored 0-100 from SEC Form 4 filings.", "SEC & financial"),
("sec-form144-insider-selling.html", "icon-form144-selling.png", "Insider Selling (Form 144)","Who is filing to sell, their role and the dollar value - the leading-indicator companion to Form 4.", "SEC & financial"),
("sec-13dg-activist-stakes.html", "icon-13dg-activist.png", "Activist Stakes (13D/G)", "Who is taking a 5%+ stake, activist vs passive, with Item 4 intent, scored by impact.", "SEC & financial"),
("smart-money-13f.html", "icon-smart-money-13f.png", "Smart Money 13F", "Quarterly hedge-fund buys, exits and cross-fund consensus from 13F filings.", "SEC & financial"),
("sec-8k-material-events.html", "icon-sec-8k.png", "8-K Material Events", "Real-time 8-K events - M&A, executive changes, earnings - classified and materiality-scored.", "SEC & financial"),
("startup-funding-form-d.html", "icon-formd-funding.png", "Startup Funding (Form D)", "New capital raises before the press release - fund noise filtered, amounts and executives parsed.", "SEC & financial"),
("biotech-catalyst-monitor.html", "icon-biotech.png", "Biotech Catalysts", "Upcoming clinical-trial readouts and results from ClinicalTrials.gov, ranked by potential impact.", "Biotech & health"),
("fda-drug-approval-monitor.html", "icon-fda-approval.png", "FDA Drug Actions", "Approvals, new indications and priority reviews from openFDA, scored as regulatory catalysts.", "Biotech & health"),
("nih-research-funding-monitor.html", "icon-nih-research.png", "NIH Research Funding", "Grant momentum by organization or research topic from NIH RePORTER - an upstream R&D signal.", "Biotech & health"),
("gov-contract-awards-monitor.html", "icon-gov-contracts.png", "Gov Contract Awards", "Recent federal contract wins per company from USAspending.gov, scored by size and recency.", "Government"),
("congress-trading-monitor.html", "icon-congress-trading.png","Congress Trading", "Recent stock trades by US House members from the official House Clerk disclosures, parsed and scored.", "Government"),
("crypto-volume-momentum-scanner.html","icon-crypto-scanner.png", "Crypto Volume & Momentum", "A crypto screener that ranks coins by unusual turnover and momentum, stablecoins filtered.", "Crypto & app"),
("app-store-review-intelligence.html", "icon-app-review.png", "App Review Intelligence", "Aspect-based sentiment, emerging issues and competitor comparison from App Store reviews.", "Crypto & app"),
]
MCP_CARD = ("datasignals-mcp.html", "icon-datasignals-mcp.png", "MCP Server",
"All 17 tools behind one Model Context Protocol endpoint for Claude, ChatGPT, Cursor and custom agents - free server, pay only per result.")
CATEGORY_ORDER = ["SEC & financial", "Biotech & health", "Government", "Crypto & app"]
ICON_BY_HTML = {p[0]: p[1] for p in PRODUCTS}
ICON_BY_HTML[MCP_CARD[0]] = MCP_CARD[1]
NAV = [
("Products", "/#products"),
("Reports", "/reports.html"),
("Pricing", "/pricing.html"),
("Performance", "/performance.html"),
("Confluence", "/confluence.html"),
("AI agents", "/datasignals-mcp.html"),
("Compare", "/compare.html"),
("Blog", "/blog.html"),
("About", "/about.html"),
]
md = markdown.Markdown(extensions=["tables", "fenced_code", "sane_lists", "attr_list", "md_in_html"])
# ---------------------------------------------------------------------------
# Custom line-art icon set (cohesive, data-tech, brand gradient stroke).
# 24x24 viewBox, stroke via shared <linearGradient id="dsg">.
# ---------------------------------------------------------------------------
# Icons carry their own gradient (unique id per call) so the diagonal gradient
# spans the whole icon, identical to the rendered Apify PNG tiles, in every browser.
GRAD_DEF = ""
_ICON_N = [0]
_ICON_PATHS = {
# SEC & financial
"sec-form4-insider-buying.html":
'<polyline points="4,16 9,11 13,14 20,6"/><polyline points="15,6 20,6 20,11"/>'
'<circle cx="9" cy="11" r="1.25"/><circle cx="13" cy="14" r="1.25"/>',
"sec-form144-insider-selling.html":
'<polyline points="4,8 9,13 13,10 20,18"/><polyline points="15,18 20,18 20,13"/>'
'<circle cx="9" cy="13" r="1.25"/><circle cx="13" cy="10" r="1.25"/>',
"sec-13dg-activist-stakes.html":
'<line x1="6.5" y1="3" x2="6.5" y2="21"/><path d="M6.5 4 H18 L14.8 8 L18 12 H6.5"/>',
"smart-money-13f.html":
'<rect x="4" y="13" width="3.6" height="7" rx="1"/><rect x="10.2" y="9" width="3.6" height="11" rx="1"/>'
'<rect x="16.4" y="4.5" width="3.6" height="15.5" rx="1"/>',
"sec-8k-material-events.html":
'<path d="M13 2.5 L5.5 13 H11 L10 21.5 L18.5 10.5 H12 Z"/>',
"startup-funding-form-d.html":
'<path d="M12 2.6c2.6 2.2 4 5.1 4 8.4 0 1.9-.8 3.5-1.7 4.6H9.7C8.8 14.5 8 12.9 8 11c0-3.3 1.4-6.2 4-8.4Z"/>'
'<circle cx="12" cy="9.6" r="1.5"/><path d="M8.2 14 5.6 16.6v3l2.6-1.5M15.8 14l2.6 2.6v3l-2.6-1.5M12 16v4.5"/>',
# Biotech & health
"biotech-catalyst-monitor.html":
'<path d="M8 3c0 4.5 8 6.5 8 9s-8 4.5-8 9"/><path d="M16 3c0 4.5-8 6.5-8 9s8 4.5 8 9"/>'
'<line x1="9.3" y1="6.6" x2="14.7" y2="6.6"/><line x1="9.3" y1="17.4" x2="14.7" y2="17.4"/>',
"fda-drug-approval-monitor.html":
'<rect x="3" y="8.5" width="12.5" height="6" rx="3"/><line x1="9.25" y1="8.5" x2="9.25" y2="14.5"/>'
'<path d="M14.5 17.5l2.2 2.2 4-4.2"/>',
"nih-research-funding-monitor.html":
'<path d="M9 3h6M10.2 3v6l-4.6 8.2A2 2 0 0 0 7.4 20.2h9.2a2 2 0 0 0 1.8-3L13.8 9V3"/>'
'<line x1="8" y1="15" x2="16" y2="15"/>',
# Government
"gov-contract-awards-monitor.html":
'<path d="M4 9 L12 4 L20 9"/><line x1="5.5" y1="9.5" x2="5.5" y2="18"/><line x1="9.8" y1="9.5" x2="9.8" y2="18"/>'
'<line x1="14.2" y1="9.5" x2="14.2" y2="18"/><line x1="18.5" y1="9.5" x2="18.5" y2="18"/>'
'<line x1="3.5" y1="20" x2="20.5" y2="20"/>',
"congress-trading-monitor.html":
'<path d="M7 11c0-3 2.2-5 5-5s5 2 5 5"/><line x1="12" y1="3" x2="12" y2="6"/><line x1="5" y1="11" x2="19" y2="11"/>'
'<line x1="6.7" y1="11.5" x2="6.7" y2="19"/><line x1="10.2" y1="11.5" x2="10.2" y2="19"/>'
'<line x1="13.8" y1="11.5" x2="13.8" y2="19"/><line x1="17.3" y1="11.5" x2="17.3" y2="19"/><line x1="4" y1="19.5" x2="20" y2="19.5"/>',
# Crypto & app
"crypto-volume-momentum-scanner.html":
'<line x1="7" y1="3.5" x2="7" y2="20.5"/><rect x="5" y="7.5" width="4" height="7.5" rx="1"/>'
'<line x1="16" y1="3.5" x2="16" y2="20.5"/><rect x="14" y="11" width="4" height="6" rx="1"/>',
"app-store-review-intelligence.html":
'<path d="M4 5.5a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H9.5l-3.5 3.5V14.5H6a2 2 0 0 1-2-2Z"/>'
'<path d="M12 6.4l1 2 2.2.3-1.6 1.55.38 2.2L12 11.4l-1.98 1.05.38-2.2L8.8 8.7l2.2-.3Z"/>',
# AI
"datasignals-mcp.html":
'<circle cx="12" cy="12" r="2.3" class="hub-core"/><circle cx="5" cy="6" r="1.7" class="hub-node n1"/>'
'<circle cx="19" cy="6" r="1.7" class="hub-node n2"/><circle cx="5" cy="18" r="1.7" class="hub-node n3"/>'
'<circle cx="19" cy="18" r="1.7" class="hub-node n4"/>'
'<line x1="6.4" y1="7.1" x2="10.2" y2="10.6"/><line x1="17.6" y1="7.1" x2="13.8" y2="10.6"/>'
'<line x1="6.4" y1="16.9" x2="10.2" y2="13.4"/><line x1="17.6" y1="16.9" x2="13.8" y2="13.4"/>',
}
def svg_icon(html, cls="dsg-ic"):
paths = _ICON_PATHS.get(html, '<circle cx="12" cy="12" r="8"/>')
extra = " hub" if html == "datasignals-mcp.html" else ""
_ICON_N[0] += 1
gid = f"dsg{_ICON_N[0]}"
grad = (f'<defs><linearGradient id="{gid}" gradientUnits="userSpaceOnUse" x1="2" y1="2" x2="22" y2="22">'
'<stop offset="0" stop-color="#14B8A6"/><stop offset=".55" stop-color="#22D3EE"/>'
'<stop offset="1" stop-color="#7af0d8"/></linearGradient></defs>')
return (f'<svg class="{cls}{extra}" viewBox="0 0 24 24" fill="none" stroke="url(#{gid})" '
f'stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">{grad}{paths}</svg>')
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def congress_example_block():
"""Rendert een echt trade-record uit de live congres-data als voorbeeld op de
productpagina (placeholder {{CONGRESS_EXAMPLE}}). Altijd vers uit de feed en
toont de exacte JSON-vorm die de API en de MCP-tools teruggeven. Uitsluitend
presentatie: leest alleen, wijzigt geen data of selectieregels."""
import json as _j
try:
d = _j.load(open("/home/krtradingpro/apify/products/_congress_data.json"))
trades = [t for t in (d.get("trades") or []) if t.get("ticker") and t.get("pdf_url")]
if not trades:
return "*(live example temporarily unavailable)*"
# Sterkste, meest sprekende record: hoogste impact, dan grootste bedrag.
t = sorted(trades, key=lambda x: (-(x.get("impact") or 0), -(x.get("amount_mid") or 0)))[0]
rec = {
"member": t.get("member", ""),
"ticker": t.get("ticker", ""),
"tx_type": t.get("tx_type", ""),
"tx_date": t.get("tx_date", ""),
"amount_low": t.get("amount_low", 0),
"amount_high": t.get("amount_high", 0),
"impact": t.get("impact", 0),
"filing_date": t.get("filing_date", ""),
"pdf_url": t.get("pdf_url", ""),
}
n = len([x for x in (d.get("trades") or []) if x.get("ticker")])
js = _j.dumps(rec, indent=2, ensure_ascii=False)
return (
"One real record from the live feed, refreshed daily. This is the exact JSON the API "
"and the MCP tools return for every trade:\n\n"
"```json\n" + js + "\n```\n\n"
"Every field is parsed straight from the official House Clerk filing linked in "
"`pdf_url`. The `impact` score (0–100) ranks how market-moving a trade is, so an "
"agent or a spreadsheet can sort it or set a threshold on it. All " + str(n) +
" scored trades in the current window share this shape."
)
except Exception:
return "*(live example temporarily unavailable)*"
def read_md(path):
txt = open(path, encoding="utf-8").read()
txt = txt.replace("{{VALUE_PROP}}", PRICING["value_prop"])
if "{{CONGRESS_EXAMPLE}}" in txt:
txt = txt.replace("{{CONGRESS_EXAMPLE}}", congress_example_block())
meta = {}
body = txt
if txt.startswith("---"):
end = txt.find("---", 3)
block = txt[3:end]
body = txt[end + 3:]
for line in block.splitlines():
m = re.match(r"(\w+):\s*(.*)", line)
if m:
meta[m.group(1)] = m.group(2).strip().strip('"')
return meta, body
def first_h1(body):
m = re.search(r"^#\s+(.+)$", body, re.M)
return (m.group(1).strip() if m else "")
def strip_first_h1(body):
return re.sub(r"^#\s+.+$", "", body, count=1, flags=re.M)
def to_html(body):
md.reset()
return md.convert(body)
def strip_keywords(body):
"""Remove visible keyword-stuffing lines (e.g. '*Keywords: a, b, c.*') and any
horizontal-rule that directly precedes them. Keyword stuffing adds no ranking
value and looks spammy to readers and to Google."""
body = re.sub(r'(?im)^\s*-{3,}\s*\n+\s*\*?keywords:.*$', '', body)
body = re.sub(r'(?im)^\s*\*?keywords:.*$', '', body)
return body
def parse_faq(body):
"""Extract (question, answer) pairs from a '## FAQ' markdown section."""
m = re.search(r'^##\s+FAQ\s*$(.*?)(?=^##\s|\Z)', body, re.M | re.S)
if not m:
return []
out = []
for q, a in re.findall(r'\*\*(.+?)\*\*\s*(.*?)(?=\n\*\*|\Z)', m.group(1), re.S):
q = q.strip()
a = re.sub(r'\s+', ' ', a).strip()
if q and a:
out.append((q, a))
return out
def rewrite_links(h):
# Jekyll-pretty internal links -> static files
h = h.replace('href="/about"', 'href="/about.html"')
h = h.replace('href="/"', 'href="/index.html"').replace('href="index.html"', 'href="/index.html"')
return h
def esc(s):
return htmllib.escape(s, quote=True)
# ---------------------------------------------------------------------------
# Shared chrome
# ---------------------------------------------------------------------------
def nav_html(active=""):
links = ""
for label, href in NAV:
cls = "nav-link active" if label.lower() == active.lower() else "nav-link"
links += f'<a class="{cls}" href="{href}">{label}</a>'
return f"""
<header class="site-head" id="site-head">
<div class="wrap head-inner">
<a class="brand" href="/index.html" aria-label="DataSignals Lab home">
<span class="brand-mark" aria-hidden="true"><span></span><span></span><span></span></span>
<span class="brand-text">DataSignals<span class="brand-accent"> Lab</span></span>
</a>
<nav class="nav" id="nav">{links}</nav>
<div class="head-cta">
<a class="btn btn-solid" href="{APIFY_PROFILE}" target="_blank" rel="noopener">Browse on Apify</a>
</div>
<button class="nav-toggle" id="nav-toggle" aria-label="Menu" aria-expanded="false"><span></span><span></span><span></span></button>
</div>
</header>"""
def footer_html():
prod_links = "".join(
f'<li><a href="/{p[0]}">{p[2]}</a></li>' for p in PRODUCTS
)
return f"""
<footer class="site-foot">
<div class="wrap foot-grid">
<div class="foot-brand">
<a class="brand" href="/index.html">
<span class="brand-mark" aria-hidden="true"><span></span><span></span><span></span></span>
<span class="brand-text">DataSignals<span class="brand-accent"> Lab</span></span>
</a>
<p class="foot-tag">Official public data, turned into scored, decision-ready signals. Self-serve, pay per result, API and AI-agent ready.</p>
<div class="foot-social">
<a href="{APIFY_PROFILE}" target="_blank" rel="noopener">Apify Store</a>
<a href="/datasignals-mcp.html">MCP server</a>
<a href="/compare.html">Compare</a>
</div>
</div>
<div class="foot-col">
<h4>Data products</h4>
<ul>{prod_links}</ul>
</div>
<div class="foot-col">
<h4>Learn</h4>
<ul>
<li><a href="/compare.html">Compare</a></li>
<li><a href="/performance.html">Performance</a></li>
<li><a href="/proof.html">Proof</a></li>
<li><a href="/confluence.html">Confluence</a></li>
<li><a href="/congress/late-filings.html">STOCK Act late filings</a></li>
<li><a href="/lobby-to-contracts.html">Lobby to contracts (beta)</a></li>
<li><a href="/press.html">Press & citations</a></li>
<li><a href="/blog.html">Blog</a></li>
<li><a href="/what-is-sec-form-144.html">What is Form 144?</a></li>
<li><a href="/13d-vs-13g-explained.html">13D vs 13G</a></li>
<li><a href="/about.html">About</a></li>
<li><a href="/datasignals-mcp.html">MCP server</a></li>
<li><a href="/privacy.html">Privacy</a></li>
<li><a href="/terms.html">Terms</a></li>
</ul>
</div>
</div>
<div class="wrap foot-bottom">
<p>© <span id="yr">2026</span> DataSignals Lab. Data for research, screening and monitoring - not investment advice. Historical patterns do not guarantee future results.</p>
<p class="foot-sources">Sources: SEC EDGAR · openFDA · ClinicalTrials.gov · USAspending.gov · US House Clerk · NIH RePORTER · CoinGecko · Apple App Store</p>
<p class="foot-contact">Questions or support: <a href="mailto:support@datasignalslab.com">support@datasignalslab.com</a></p>
</div>
</footer>"""
PAGE_TMPL = """<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>__TITLE__</title>
<meta name="description" content="__DESC__">
__VERIFY__<link rel="canonical" href="__CANON__">
<meta name="theme-color" content="#070d1c">
<meta property="og:type" content="__OGTYPE__">
<meta property="og:site_name" content="DataSignals Lab">
<meta property="og:title" content="__OGTITLE__">
<meta property="og:description" content="__DESC__">
<meta property="og:url" content="__CANON__">
<meta property="og:image" content="__BASE____OGIMG__">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="__OGTITLE__">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="__OGTITLE__">
<meta name="twitter:description" content="__DESC__">
<meta name="twitter:image" content="__BASE____OGIMG__">
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon-16x16.png">
<link rel="icon" type="image/svg+xml" href="/assets/datasignalslab-profile.svg">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/apple-touch-icon.png">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=Space+Grotesk:wght@500;600;700&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/assets/site.css?v=__ASSETV__">
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"Organization","name":"DataSignals Lab","url":"https://datasignalslab.com","logo":"https://datasignalslab.com/assets/favicon-512.png","description":"Self-serve data products that turn official public sources (SEC EDGAR, openFDA, ClinicalTrials.gov, CoinGecko, Apple App Store) into scored, structured signals for traders, quants, fintech and AI agents.","sameAs":["https://apify.com/datasignalslab"]}
</script>
__JSONLD__
</head>
<body class="__BODYCLASS__">
__GRAD__
__NAV__
<main id="top">
__BODY__
</main>
__FOOT__
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/gsap.min.js" defer></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/ScrollTrigger.min.js" defer></script>
<script src="/assets/site.js?v=__ASSETV__" defer></script>
</body>
</html>
"""
_ASSET_V = None
def asset_v():
"""Content-hash van site.css+site.js -> cache-busting querystring.
Elke deploy met gewijzigde assets krijgt zo automatisch verse CSS/JS bij
alle bezoekers (lost het stale-cache-probleem van 2 juli op)."""
global _ASSET_V
if _ASSET_V is None:
import hashlib
h = hashlib.md5()
for f in ("assets/site.css", "assets/site.js"):
h.update(open(os.path.join(ROOT, f), "rb").read())
_ASSET_V = h.hexdigest()[:10]
return _ASSET_V
def render_page(title, desc, canon_path, body, active="", extra_jsonld="", og_type="website", bodyclass="", og_title=None, og_image="/assets/og/og-default.png"):
page = PAGE_TMPL
canon = BASE + canon_path
repl = {
"__ASSETV__": asset_v(),
"__TITLE__": esc(title),
"__OGTITLE__": esc(og_title or title),
"__DESC__": esc(desc),
"__CANON__": canon,
"__OGIMG__": og_image,
"__BASE__": BASE,
"__OGTYPE__": og_type,
"__JSONLD__": extra_jsonld,
"__GRAD__": GRAD_DEF,
"__NAV__": nav_html(active),
"__FOOT__": footer_html(),
"__BODY__": body,
"__BODYCLASS__": bodyclass,
"__VERIFY__": verify_meta(),
}
for k, v in repl.items():
page = page.replace(k, v)
page = page.replace("</body>", analytics_snippet() + "</body>")
return add_referral(page)
_VERIFY = None
def verify_meta():
"""Sectie 11: verificatie-metatags voor Google Search Console en Bing
Webmaster. Injecteert pas zodra config/search_console.json echte tokens
heeft; placeholders lekken nooit naar de output. De HTML-bestandsvariant
gaat via config/verification/ (zie main), de DNS-TXT-variant staat als
stappenplan in TODO.md."""
global _VERIFY
if _VERIFY is None:
_VERIFY = ""
try:
cfg = _json_pricing.load(open(os.path.join(ROOT, "config", "search_console.json")))
g = cfg.get("google_site_verification", "")
b = cfg.get("bing_msvalidate_01", "")
if g and not g.startswith("TODO"):
_VERIFY += f'<meta name="google-site-verification" content="{g}">\n'
if b and not b.startswith("TODO"):
_VERIFY += f'<meta name="msvalidate.01" content="{b}">\n'
except Exception:
_VERIFY = ""
return _VERIFY
_ANALYTICS = None
def analytics_snippet():
"""Sectie 16: GoatCounter (cookieloos, geen banner nodig). Injecteert pas
zodra config/analytics.json een echte sitecode heeft; placeholders lekken
nooit naar de output (check_consistency waakt daar ook over)."""
global _ANALYTICS
if _ANALYTICS is None:
_ANALYTICS = ""
try:
cfg = _json_pricing.load(open(os.path.join(ROOT, "config", "analytics.json")))
code = cfg.get("goatcounter_code", "")
if code and not code.startswith("TODO"):
_ANALYTICS = (f'<script data-goatcounter="https://{code}.goatcounter.com/count" '
f'async src="https://gc.zgo.at/count.js"></script>')
except Exception:
_ANALYTICS = ""
return _ANALYTICS
def jsonld_block(d):
import json
return '<script type="application/ld+json">' + json.dumps(d, separators=(",", ":")) + "</script>"
def write(rel, content):
path = os.path.join(OUT, rel)
os.makedirs(os.path.dirname(path), exist_ok=True)
open(path, "w", encoding="utf-8").write(content)
# ---------------------------------------------------------------------------
# Homepage
# ---------------------------------------------------------------------------
# ---------------------------------------------------------------------------
# Premium reports — gedeelde kaarten (homepage + /reports.html)
# ---------------------------------------------------------------------------
# Single source of truth: config/pricing.json (PROJECTINSTRUCTIE_v4.0.md sectie 3).
# Alle prijzen, limieten en checkout-URLs komen hieruit; check_consistency.py
# faalt de build bij elke afwijking in de output.
import json as _json_pricing
PRICING = _json_pricing.load(open(os.path.join(ROOT, "config", "pricing.json")))
_RP = PRICING["reports"]
CHECKOUT = {
"formd_paid": _RP["formd"]["checkout_snapshot"],
"formd_free": _RP["formd"]["checkout_preview"],
"f13_paid": _RP["13f"]["checkout_snapshot"],
"f13_free": _RP["13f"]["checkout_preview"],
"congress_paid": _RP["congress"]["checkout_snapshot"],
"congress_free": _RP["congress"]["checkout_preview"],
}
SNAPSHOT_PRICE = PRICING["tiers"]["snapshot"]["price_usd"]
PRO_MONTH = PRICING["tiers"]["pro"]["price_month_usd"]
PRO_YEAR = PRICING["tiers"]["pro"]["price_year_usd"]
MCP_FREE_CALLS = PRICING["tiers"]["free"]["mcp_free_calls_per_month"]
ACTOR_RESULT = f"${PRICING['actors']['price_per_result_usd']:.2f}"
# Kernzin (RONDE_FINAL punt 2): een bron, overal identiek, bewaakt door
# check_consistency.py. Markdown-bronnen gebruiken de placeholder {{VALUE_PROP}}.
VALUE_PROP = PRICING["value_prop"]
# Fondsenlijst 13F: single source config/funds13f.json (v4.0 sectie 7).
N_FUNDS_13F = len(_json_pricing.load(open(os.path.join(ROOT, "config", "funds13f.json")))["funds"])
# Stromenteller: single source config/streams.json (RONDE_FINAL punt 6.3);
# nieuwe stromen tellen automatisch mee op de homepage en in /api/streams.json.
N_STREAMS = len(_json_pricing.load(open(os.path.join(ROOT, "config", "streams.json")))["streams"])
def _fmt_usd(v):
v = float(v)
if v >= 1e9: return f"${v/1e9:.1f}B"
if v >= 1e6: return f"${v/1e6:.0f}M"
return f"${v/1e3:.0f}K"
def _tcase(s):
return " ".join(w.capitalize() if not (w.isupper() and len(w) <= 4) else w
for w in str(s).split())
def _report_peeks():
"""Echte top-rijen uit de rapportdata: de 'live sample' in de kaarten.
Ververst automatisch mee met elke deploy (dagelijkse cron). Faalt stil."""
import json as _json
formd, f13, congress = "", "", ""
try:
d = _json.load(open("/home/krtradingpro/apify/products/_formd_data.json"))
rs = [r for r in d if r.get("type") == "capital_raise" and float(r.get("amount_sold") or 0) > 0]
total = len([r for r in d if r.get("type") == "capital_raise"])
rs.sort(key=lambda r: (-int(r.get("score", 0)), -float(r.get("amount_sold") or 0)))
rows = "".join(
f'<div class="pk-row"><span class="pk-name">{esc(_tcase(r["issuer"]))}</span>'
f'<span class="pk-val">{_fmt_usd(r["amount_sold"])}</span>'
f'<span class="pk-chip">{r.get("score","")}</span></div>'
for r in rs[:3])
if rows:
formd = (f'<div class="report-peek mono"><div class="pk-head">Live sample · latest filings</div>'
f'{rows}<div class="pk-more">+ {max(0, total-3)} more inside</div></div>')
except Exception:
pass
try:
d = _json.load(open("/home/krtradingpro/apify/products/_13f_data.json"))
picks = next((x.get("picks") for x in d if x.get("type") == "consensus"), [])[:3]
rows = "".join(
f'<div class="pk-row"><span class="pk-name">{esc(_tcase(p["issuer"]))}</span>'
f'<span class="pk-val">{p.get("funds_holding","?")} funds</span>'
f'<span class="pk-chip">{p.get("buyers","?")} buying</span></div>'
for p in picks)
if rows:
f13 = (f'<div class="report-peek mono"><div class="pk-head">Live sample · consensus ranking</div>'
f'{rows}<div class="pk-more">50 ranked stocks inside</div></div>')
except Exception:
pass
try:
d = _json.load(open("/home/krtradingpro/apify/products/_congress_data.json"))
ts = d.get("trades") or []
rows = "".join(
f'<div class="pk-row"><span class="pk-name">{esc(t["member"])} · {esc(t.get("ticker") or "n/a")}</span>'
f'<span class="pk-val">{_fmt_usd(t.get("amount_mid") or 0)}</span>'
f'<span class="pk-chip">{t.get("impact","")}</span></div>'
for t in ts[:3])
if rows:
congress = (f'<div class="report-peek mono"><div class="pk-head">Live sample · latest disclosures</div>'
f'{rows}<div class="pk-more">+ {max(0, len(ts)-3)} more inside</div></div>')
except Exception:
pass
return formd, f13, congress
def _cover_svg(title, source, slug):
"""Genereert een zelfstandige 16:9 SVG-cover in de huisstijl voor een rapport.
Vervangt de ontbrekende cover-PNG's; geen externe assets, rendert altijd."""
words = title.split()
line1, line2 = title, ""
if len(title) > 16 and len(words) > 1:
# Split op ~helft, op woordgrens, zodat twee nette regels ontstaan.
best, half = 0, len(title) / 2
acc = 0
for i, w in enumerate(words[:-1]):
acc += len(w) + 1
if abs(acc - half) < abs(best - half):
best, split_at = acc, i + 1
line1 = " ".join(words[:split_at])
line2 = " ".join(words[split_at:])
t1 = htmllib.escape(line1)
t2 = htmllib.escape(line2)
src = htmllib.escape(source.upper())
y1, y2 = (430, 545) if t2 else (490, 0)
line2_svg = (f'<text x="110" y="{y2}" fill="#ffffff" font-family="Space Grotesk, Inter, sans-serif" '
f'font-size="104" font-weight="700">{t2}</text>') if t2 else ""
return (
f'<svg class="report-cover-svg" viewBox="0 0 1600 900" width="100%" height="100%" '
f'preserveAspectRatio="xMidYMid slice" role="img" '
f'aria-label="{htmllib.escape(title)} — {src} report cover" '
f'style="display:block">'
f'<defs>'
f'<linearGradient id="cbg{slug}" x1="0" y1="0" x2="1" y2="1">'
f'<stop offset="0" stop-color="#0a1a26"/><stop offset="1" stop-color="#0c2130"/></linearGradient>'
f'<linearGradient id="cac{slug}" x1="0" y1="0" x2="1" y2="0">'
f'<stop offset="0" stop-color="#14B8A6"/><stop offset="1" stop-color="#22D3EE"/></linearGradient>'
f'</defs>'
f'<rect width="1600" height="900" fill="url(#cbg{slug})"/>'
f'<rect x="0" y="0" width="1600" height="10" fill="url(#cac{slug})"/>'
f'<path d="M110 690 L430 600 L720 660 L1010 470 L1300 540 L1520 360" fill="none" '
f'stroke="url(#cac{slug})" stroke-width="7" opacity="0.35" stroke-linecap="round" stroke-linejoin="round"/>'
f'<circle cx="1010" cy="470" r="16" fill="#22D3EE"/>'
f'<text x="110" y="300" fill="#22D3EE" font-family="JetBrains Mono, monospace" '
f'font-size="44" letter-spacing="8">{src}</text>'
f'<text x="110" y="{y1}" fill="#ffffff" font-family="Space Grotesk, Inter, sans-serif" '
f'font-size="104" font-weight="700">{t1}</text>'
f'{line2_svg}'
f'<text x="110" y="820" fill="#7fa6b8" font-family="Inter, sans-serif" font-size="38" '
f'font-weight="600" letter-spacing="1">DataSignals Lab</text>'
f'</svg>'
)
# Rapporten waarvoor een cover-SVG wordt gegenereerd: (bestandsslug, titel, bron).
REPORT_COVERS = [
("formd-startup-raises", "Startup Capital Raises", "SEC Form D"),
("13f-consensus-q1-2026", "Smart-Money 13F Consensus", "SEC 13F"),
("congress-trading", "Congress Stock Trades", "House PTRs"),
]
def write_report_covers():
"""Schrijft de gegenereerde SVG-covers naar public/dl/ (de img-tags wijzen ernaar)."""
os.makedirs(os.path.join(OUT, "dl"), exist_ok=True)
for slug, title, source in REPORT_COVERS:
cid = re.sub(r"[^a-z0-9]", "", slug)
write(os.path.join("dl", f"cover-{slug}.svg"), _cover_svg(title, source, cid))
def report_cards_html():
pk_formd, pk_f13, pk_congress = _report_peeks()
return f"""<div class="report-grid">
<article class="report-card reveal">
<a class="report-cover" href="{CHECKOUT['formd_free']}" target="_blank" rel="noopener"><img src="/assets/cover-formd-startup-raises.png" alt="Startup Capital Raises, SEC Form D report cover" loading="lazy"></a>
<div class="report-body">
<span class="report-price">${SNAPSHOT_PRICE} snapshot · or all reports in <a href="/pricing.html">Pro</a></span>
<h3>Startup Capital Raises <span class="report-src">SEC Form D</span></h3>
{pk_formd}
<p>The biggest new private capital raises, days before the press. Pooled investment funds filtered out, ranked by a funding score. Refreshes daily.</p>
<div class="report-actions">
<a class="btn btn-solid" href="{CHECKOUT['formd_paid']}" target="_blank" rel="noopener">Get the report for ${SNAPSHOT_PRICE}</a>
<a class="btn btn-ghost" href="{CHECKOUT['formd_free']}" target="_blank" rel="noopener">Free preview</a>
</div>
</div>
</article>
<article class="report-card reveal">
<a class="report-cover" href="{CHECKOUT['f13_free']}" target="_blank" rel="noopener"><img src="/assets/cover-13f-consensus-q1-2026.png" alt="Smart-Money 13F Consensus report cover" loading="lazy"></a>
<div class="report-body">
<span class="report-price">${SNAPSHOT_PRICE} snapshot · or all reports in <a href="/pricing.html">Pro</a></span>
<h3>Smart-Money 13F Consensus <span class="report-src">SEC 13F</span></h3>
{pk_f13}
<p>What {N_FUNDS_13F} of the most-watched hedge funds bought, sold and crowded into last quarter, in one cross-fund consensus ranking. Refreshes each quarter.</p>
<div class="report-actions">
<a class="btn btn-solid" href="{CHECKOUT['f13_paid']}" target="_blank" rel="noopener">Get the report for ${SNAPSHOT_PRICE}</a>
<a class="btn btn-ghost" href="{CHECKOUT['f13_free']}" target="_blank" rel="noopener">Free preview</a>
</div>
</div>
</article>
<article class="report-card reveal">
<a class="report-cover" href="{CHECKOUT['congress_free']}" target="_blank" rel="noopener"><img src="/assets/cover-congress-trading.png" alt="Congress Stock Trades, House PTR report cover" loading="lazy"></a>
<div class="report-body">
<span class="report-price">${SNAPSHOT_PRICE} snapshot · or all reports in <a href="/pricing.html">Pro</a></span>
<h3>Congress Stock Trades <span class="report-src">House PTRs</span></h3>
{pk_congress}
<p>Every stock trade disclosed by U.S. House members, ranked by impact, with consensus stocks (tickers multiple members traded) and the most active traders. Refreshes weekly.</p>
<div class="report-actions">
<a class="btn btn-solid" href="{CHECKOUT['congress_paid']}" target="_blank" rel="noopener">Get the report for ${SNAPSHOT_PRICE}</a>
<a class="btn btn-ghost" href="{CHECKOUT['congress_free']}" target="_blank" rel="noopener">Free preview</a>
</div>
</div>
</article>
</div>"""
def build_ticker():
"""Live ticker met echte Form D-raises + Congress-trades (koop groen / verkoop rood)
uit de rapport-datamodellen. Wordt bij elke deploy opnieuw gegenereerd (dagelijkse
formd-cron + wekelijkse congress-cron verversen 'm dus mee). Faalt stil per bron."""
import json as _json
def usd(v):
v = float(v)
if v >= 1e9: return f"${v/1e9:.1f}B"
if v >= 1e6: return f"${v/1e6:.0f}M"
return f"${v/1e3:.0f}K"
def tc(s):
return " ".join(w.capitalize() if not (w.isupper() and len(w) <= 4) else w
for w in str(s).split())
formd_items, congress_items = [], []
try:
data = _json.load(open("/home/krtradingpro/apify/products/_formd_data.json"))
raises = [r for r in data if r.get("type") == "capital_raise"
and float(r.get("amount_sold") or 0) >= 1_000_000]
raises.sort(key=lambda r: -float(r.get("amount_sold") or 0))
formd_items = [
f'<span class="tk-item"><b>{esc(tc(r.get("issuer","")))}</b> raised {usd(r.get("amount_sold"))}</span>'
for r in raises[:6]]
except Exception:
pass
try:
d = _json.load(open("/home/krtradingpro/apify/products/_congress_data.json"))
ts = [t for t in (d.get("trades") or []) if t.get("ticker")
and t.get("tx_type") in ("Purchase", "Sale")]
congress_items = [
(f'<span class="tk-item">'
f'<span class="{"tk-buy" if t["tx_type"] == "Purchase" else "tk-sell"}">'
f'{"▲" if t["tx_type"] == "Purchase" else "▼"} {esc(t["ticker"])}</span> '
f'Rep. {esc(t["member"].split()[-1])} '
f'{"bought" if t["tx_type"] == "Purchase" else "sold"} '
f'${t.get("amount_low",0):,}–${t.get("amount_high",0):,}</span>')
for t in ts[:6]]
except Exception:
pass
# Afwisselen: raise, trade, raise, trade... (wat over is achteraan)
items_list = []
for a, b in zip(formd_items, congress_items):
items_list += [a, b]
items_list += formd_items[len(congress_items):] + congress_items[len(formd_items):]
if len(items_list) < 4:
return ""
items = "".join(i + '<span class="tk-sep">·</span>' for i in items_list)
lead = ('<span class="tk-live"><span class="tk-dot"></span>Live · SEC & Congress filings</span>'
'<span class="tk-sep">·</span>')
half = lead + items
return (f'<a class="ticker" href="/#reports" aria-label="Latest startup capital raises and Congress trades">'
f'<div class="tk-track">{half}{half}</div></a>')
def build_home():
# product grid grouped by category
sections = ""
for cat in CATEGORY_ORDER:
cards = ""
for hpage, icon, title, blurb, c in PRODUCTS:
if c != cat:
continue
cards += f"""
<a class="card reveal" href="/{hpage}">
<span class="card-ic">{svg_icon(hpage)}</span>
<h3>{esc(title)}</h3>
<p>{esc(blurb)}</p>
<span class="card-go">View product →</span>
</a>"""
sections += f"""
<div class="cat-row">
<h3 class="cat-label">{esc(cat)}</h3>
<div class="card-grid">{cards}</div>
</div>"""
stats = f"""
<div class="stat-strip wrap reveal">
<div class="stat"><b>{len(PRODUCTS) + 1}</b><span>data products</span></div>
<div class="stat"><b>{len(PRODUCTS) + 2}</b><span>tools over MCP</span></div>
<div class="stat"><b>3</b><span>premium reports</span></div>
<div class="stat"><b>{N_STREAMS}</b><span>signal streams, hash-chained daily</span></div>
</div>"""
mcp = f"""
<section class="agents wrap reveal" id="agents">
<div class="agents-card">
<div class="agents-text">
<span class="eyebrow">For AI agents</span>
<h2>One MCP endpoint. 15 live financial-data tools.</h2>
<p>Connect Claude, ChatGPT, Cursor or any MCP-capable agent once and it can pull real-time SEC, FDA, clinical-trial, government and crypto data on demand - parsed and scored, never raw HTML. One free call to the flagship confluence_signals ranks the strongest cross-source signals right now. The server is free and you only pay the underlying tools' standard {ACTOR_RESULT} per result.</p>
<div class="btn-row">
<a class="btn btn-solid" href="/datasignals-mcp.html">Explore the MCP server</a>
<a class="btn btn-ghost" href="{APIFY_PROFILE}/datasignals-mcp" target="_blank" rel="noopener">Get it on Apify</a>
</div>
<div class="agents-logos">
<span>LangChain</span><span>LlamaIndex</span><span>Flowise</span><span>Zapier</span><span>Make</span><span>Webhooks</span>
</div>
</div>
<div class="agents-visual" aria-hidden="true">
<span class="agents-ic">{svg_icon(MCP_CARD[0], cls="dsg-ic")}</span>
<code class="code-pop">agent.call("hedge_fund_13f", ticker="NVDA")</code>
</div>
</div>
</section>"""
why = """
<section class="why wrap reveal">
<h2 class="sec-title">Why DataSignals Lab</h2>
<div class="why-grid">
<div class="why-item"><div class="why-ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="3"/></svg></div><h4>Official sources only</h4><p>SEC EDGAR, openFDA, ClinicalTrials.gov, USAspending, CoinGecko, Apple App Store. Free, legal, no personal data.</p></div>
<div class="why-item"><div class="why-ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="16" height="16" rx="3"/><path d="M8 13l3 3 5-7"/></svg></div><h4>Transparent scoring</h4><p>Every 0-100 score is explained, so you can verify and reproduce it - no black boxes.</p></div>
<div class="why-item"><div class="why-ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M6 18 18 6"/><path d="M9 6h9v9"/></svg></div><h4>Verifiable</h4><p>Every result links back to the original filing or source. Trust, then check.</p></div>
<div class="why-item"><div class="why-ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M20 12a8 8 0 1 1-2.34-5.66"/><path d="M20 4v4h-4"/></svg></div><h4>Reliable</h4><p>Each product is monitored daily and built on stable, official APIs.</p></div>
<div class="why-item"><div class="why-ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2.5 5.5 13H11L10 21.5 18.5 10.5H12Z"/></svg></div><h4>Self-serve</h4><p>Pay per result on the data tools, or one <a href="/pricing.html">Pro plan</a> for all three reports. API and AI-agent ready.</p></div>
<div class="why-item"><div class="why-ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M12 4v2M12 18v2M4 12h2M18 12h2M6.3 6.3l1.4 1.4M16.3 16.3l1.4 1.4M17.7 6.3l-1.4 1.4M7.7 16.3l-1.4 1.4"/></svg></div><h4>Drops into your stack</h4><p>JSON output, webhooks, schedules, Zapier and Make - or call it as an agent tool.</p></div>
</div>
</section>"""
hero = f"""
<section class="hero">
<div class="hero-bg" aria-hidden="true"><span class="blob b1"></span><span class="blob b2"></span><span class="grid-overlay"></span><canvas id="sig" class="sig"></canvas></div>
<div class="wrap hero-inner">
<span class="eyebrow reveal">SEC · FDA · clinical-trial · gov · crypto · app data</span>
<h1 class="reveal" id="hero-h1">Official public data, turned into <span class="grad">scored signals</span>.</h1>
<p class="hero-sub reveal">{esc(VALUE_PROP)}</p>
<p class="hero-sub reveal">DataSignals Lab takes official datasets - SEC EDGAR, openFDA, ClinicalTrials.gov, USAspending, the App Store - and adds a transparent analysis layer. You get an answer, not a pile of rows. Pay per result, call it from an API, or wire it straight into an AI agent.</p>
<div class="btn-row reveal">
<a class="btn btn-solid btn-lg" href="#products">Explore the products</a>
<a class="btn btn-ghost btn-lg" href="/datasignals-mcp.html">Free MCP for agents</a>
</div>
<p class="hero-meta reveal">Verifiable sources · free previews · built for traders, quants, fintech and researchers</p>
</div>
<div class="scroll-cue" aria-hidden="true"><span></span></div>
</section>"""
sigviz = """
<section class="sigviz wrap" id="how-signals">
<div class="sec-head reveal">
<h2 class="sec-title">From raw filing to <span class="grad">scored signal</span></h2>
<p class="sec-lead">Every product runs the same pipeline: pull the official source, parse the filing, score it 0–100, return clean JSON. Scroll to watch a signal take shape.</p>
</div>
<div class="viz-panel reveal">
<div class="viz-head mono"><span class="tk-dot"></span>SEC EDGAR → PARSE → SCORE → JSON</div>
<div class="viz-stage">
<svg id="vizsvg" viewBox="0 0 800 300" preserveAspectRatio="none" role="img" aria-label="Example: share price line with scored signals from official filings">
<defs>
<linearGradient id="vzstroke" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" stop-color="#14B8A6"/><stop offset="1" stop-color="#22D3EE"/>
</linearGradient>
<linearGradient id="vzfill" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="rgba(34,211,238,.16)"/><stop offset="1" stop-color="rgba(34,211,238,0)"/>
</linearGradient>
</defs>
<line class="vz-grid" x1="0" y1="80" x2="800" y2="80"/>
<line class="vz-grid" x1="0" y1="160" x2="800" y2="160"/>
<line class="vz-grid" x1="0" y1="240" x2="800" y2="240"/>
<path id="vzarea" fill="url(#vzfill)" stroke="none"
d="M0,232 C60,224 95,246 145,238 C195,230 215,196 265,200 C315,204 335,162 385,156 C435,150 455,182 505,162 C555,142 575,104 625,98 C675,92 705,124 755,108 L800,102 L800,300 L0,300 Z"/>
<path id="vzpath" fill="none" stroke="url(#vzstroke)" stroke-width="2.5" stroke-linecap="round"
d="M0,232 C60,224 95,246 145,238 C195,230 215,196 265,200 C315,204 335,162 385,156 C435,150 455,182 505,162 C555,142 575,104 625,98 C675,92 705,124 755,108 L800,102"/>
</svg>
<div class="vz-overlay" aria-hidden="true">
<div class="vz-mk down" style="left:33.1%;top:66.7%"><span class="vz-pt"></span><span class="vz-tag2 mono">FORM 4 · CLUSTER BUY · 84</span></div>
<div class="vz-mk up" style="left:63.1%;top:54%"><span class="vz-pt"></span><span class="vz-tag2 mono">8-K · MATERIAL EVENT · 71</span></div>
<div class="vz-mk down last" style="left:94.4%;top:36%"><span class="vz-pt"></span><span class="vz-tag2 mono">13F · CONSENSUS ADD · 92</span></div>
</div>
</div>
<div class="viz-legend mono"><span class="lg-line"></span>share price (example)<span class="lg-gap"></span><span class="lg-dot"></span>scored signal from an official filing</div>
<div class="viz-foot mono">score = size × freshness × conviction · every result links to the official filing</div>
</div>
</section>"""
products_sec = f"""
<section class="products wrap" id="products">
<div class="sec-head reveal">
<h2 class="sec-title">The data products</h2>
<p class="sec-lead">Thirteen self-serve data feeds plus one free MCP server, fourteen products in total. Each feed takes a clean official source and returns structured, scored, decision-ready output - with a link back to the original filing. The MCP server bundles the thirteen feeds for AI agents and adds the free confluence_signals flagship, a multi-signal company scan, a name-to-ticker resolver and a usage meter, seventeen tools in one endpoint.</p>
</div>
{sections}
<div class="cat-row">
<h3 class="cat-label">For AI agents</h3>
<div class="card-grid">
<a class="card card-mcp reveal" href="/{MCP_CARD[0]}">
<span class="card-ic">{svg_icon(MCP_CARD[0])}</span>
<h3>{esc(MCP_CARD[2])} <span class="badge">free</span></h3>
<p>{esc(MCP_CARD[3])}</p>
<span class="card-go">View MCP server →</span>
</a>
</div>
</div>
</section>"""
cta = """
<section class="endcta reveal">
<div class="wrap endcta-inner">
<h2>Start with a single run.</h2>
<p>No account games, no demos to sit through. Pick a feed, run it, pay only for the results you get back.</p>
<div class="btn-row">
<a class="btn btn-solid btn-lg" href="#products">Browse all products</a>
<a class="btn btn-ghost btn-lg" href="/compare.html">How we compare</a>
</div>
</div>
</section>"""
reports_sec = f"""
<section class="reports wrap" id="reports">
<div class="sec-head reveal">
<h2 class="sec-title">Premium reports</h2>
<p class="sec-lead">The same official sources, distilled into one clean, ranked document you can read in minutes. Try a free preview, buy a ${SNAPSHOT_PRICE} snapshot, or get all three refreshed monthly with <a href="/pricing.html">DataSignals Pro</a>.</p>
</div>
{report_cards_html()}
<p class="report-note">Free previews collect your email and unlock the full report · secure checkout by Lemon Squeezy · instant access</p>
</section>"""
trust = """
<div class="trust-bar wrap reveal" aria-label="Listed on">
<span class="tb-label mono">Listed on</span>
<a class="tb-chip" href="https://apify.com/datasignalslab" target="_blank" rel="noopener"><span class="tb-ck">✓</span>Apify Store</a>
<a class="tb-chip" href="/datasignals-mcp.html"><span class="tb-ck">✓</span>Official MCP Registry</a>
<a class="tb-chip" href="https://smithery.ai/servers/datasignalslab/datasignals-lab" target="_blank" rel="noopener"><span class="tb-ck">✓</span>Smithery</a>
<span class="tb-chip tb-static">Secure checkout · Lemon Squeezy · Merchant of Record</span>
</div>"""
body = hero + build_ticker() + trust + stats + sigviz + reports_sec + products_sec + mcp + why + cta
title = "SEC, FDA & Crypto Data as Scored Signals | DataSignals Lab"
desc = "Decision-ready data feeds from official public sources: SEC insider, 13F, 8-K, Form D, FDA, clinical-trial, congress, crypto and app-review signals. Pay per result."
website = jsonld_block({
"@context": "https://schema.org", "@type": "WebSite",
"name": "DataSignals Lab", "url": BASE,
"description": desc,
"publisher": {"@type": "Organization", "name": "DataSignals Lab", "url": BASE},
})
write("index.html", render_page(title, desc, "/", body, active="Products",
bodyclass="home", extra_jsonld=website,
og_image="/assets/og/og-home.png"))
# ---------------------------------------------------------------------------
# Article-style pages (products, guides, compare, about)
# ---------------------------------------------------------------------------
def build_reports_page():
"""Eigen SEO-pagina voor de premium rapporten (naast de homepage-sectie):
rankt op 'form d report' / '13f consensus report', met Product-JSON-LD."""
import json as _json
cards = report_cards_html()
body = f"""
<section class="reports wrap" id="reports" style="padding-top:2.4rem">
<nav class="crumb"><a href="/index.html">Home</a> <span>/</span> <span class="crumb-cur">Reports</span></nav>
<div class="sec-head reveal">
<h2 class="sec-title" style="font-size:clamp(2rem,5vw,3rem)">Premium <span class="grad">SEC data reports</span></h2>
<p class="sec-lead">The same official sources behind our live data products, distilled into one clean, ranked document you can read in minutes. Start with a free preview, buy one report as a ${SNAPSHOT_PRICE} snapshot, or get all three refreshed monthly with <a href="/pricing.html">DataSignals Pro</a>.</p>
</div>
{cards}
<p class="report-note">Free previews collect your email and unlock the full report · secure checkout by Lemon Squeezy (Merchant of Record) · instant access</p>
<div class="sec-head reveal" style="margin-top:3.2rem">
<h2 class="sec-title" style="font-size:1.6rem">What's inside</h2>
</div>
<div class="why-grid">
<div class="why-item reveal">
<h4>Startup Capital Raises, SEC Form D · ${SNAPSHOT_PRICE}</h4>
<p>Every qualifying raise ($1M+) ranked by a funding score (size × freshness × type). Amounts raised and offered, industry, securities type, state and filing date. The biggest raises in detail with disclosed executives, and a direct link to the official SEC filing for every row. Pooled investment funds are filtered out, so you see the real operating-company startup signal, days before (and often without) any press.</p>
</div>
<div class="why-item reveal">
<h4>Smart-Money 13F Consensus, SEC 13F · ${SNAPSHOT_PRICE}</h4>
<p>The latest 13F filings of {N_FUNDS_13F} of the most-watched managers, from Berkshire Hathaway and Citadel to Duquesne and Point72, distilled into a cross-fund consensus table: 50 stocks ranked by conviction (how many funds hold + buying activity), plus each fund's biggest new positions, adds, exits and trims. Every figure traceable to the official EDGAR filing.</p>
</div>
<div class="why-item reveal">
<h4>Congress Stock Trades, House PTRs · ${SNAPSHOT_PRICE}</h4>
<p>Every stock trade disclosed by U.S. House members this period, parsed from the official House Clerk filings and ranked by an impact score (size × freshness). Consensus stocks (the tickers multiple members traded, with buy/sell lean), the most active members, and the biggest trades in detail. Every trade links to the official PTR filing.</p>
</div>
</div>
<div class="sec-head reveal" style="margin-top:3.2rem">
<h2 class="sec-title" style="font-size:1.6rem">FAQ</h2>
</div>
<div class="faq reveal">
<div class="faq-item"><p class="faq-q">Snapshot or Pro, what is the difference?</p>
<p class="faq-a">A snapshot is a one-off ${SNAPSHOT_PRICE} purchase of one report: the current edition plus 30 days of updates. DataSignals Pro is ${PRO_MONTH} a month (or ${PRO_YEAR} a year) for all three reports, refreshed monthly, plus MCP access for AI agents and email alerts. See the <a href="/pricing.html">pricing page</a>.</p></div>
<div class="faq-item"><p class="faq-q">Where does the data come from?</p>
<p class="faq-a">Directly from official public sources: SEC EDGAR Form D and Form 13F filings, and the U.S. House Clerk financial-disclosure feed. Every row in a report links back to the original filing so you can verify it yourself.</p></div>
<div class="faq-item"><p class="faq-q">Is this investment advice?</p>
<p class="faq-a">No. The reports are data and research, not investment advice and not an offer or solicitation. Amounts in Form D filings are self-reported by the issuer; historical 13F positioning does not guarantee future results.</p></div>
<div class="faq-item"><p class="faq-q">Need this live or on demand instead?</p>
<p class="faq-a">Yes. The same signals are available as self-serve <a href="/#products">data products</a> on Apify, and AI agents can call them through our free MCP server. The reports are the curated layer on top: cross-filing analysis, ranking and context in one finished document.</p></div>
</div>
<div class="btn-row reveal" style="margin-top:2.4rem">
<a class="btn btn-solid btn-lg" href="{CHECKOUT['formd_free']}" target="_blank" rel="noopener">Try the free Form D preview</a>
<a class="btn btn-ghost btn-lg" href="{CHECKOUT['f13_free']}" target="_blank" rel="noopener">Try the free 13F preview</a>
<a class="btn btn-ghost btn-lg" href="{CHECKOUT['congress_free']}" target="_blank" rel="noopener">Try the free Congress preview</a>
</div>
</section>"""
prods = ""
for name, desc, img, url in (
("Startup Capital Raises, SEC Form D Report",
"The biggest new private capital raises from SEC Form D filings, ranked by a funding score, days before the press. Refreshes daily.",
"/assets/cover-formd-startup-raises.png", CHECKOUT["formd_paid"]),
("Smart-Money 13F Consensus Report",
f"What {N_FUNDS_13F} of the most-watched hedge funds bought, sold and crowded into last quarter, one cross-fund consensus ranking. Refreshes quarterly.",
"/assets/cover-13f-consensus-q1-2026.png", CHECKOUT["f13_paid"]),
("Congress Stock Trades Report, House PTRs",
"Every stock trade disclosed by U.S. House members, ranked by impact, with consensus stocks and the most active members. Refreshes weekly.",
"/assets/cover-congress-trading.png", CHECKOUT["congress_paid"]),
):
prods += jsonld_block({
"@context": "https://schema.org", "@type": "Product",
"name": name, "description": desc, "image": BASE + img,
"brand": {"@type": "Brand", "name": "DataSignals Lab"},
"offers": {"@type": "Offer", "price": f"{SNAPSHOT_PRICE:.2f}", "priceCurrency": "USD",
"url": url, "availability": "https://schema.org/InStock",
# Digitale download: geen fysieke verzending, geen retour
# (silences GSC merchant-listing warnings, eerlijk gemarkeerd)
"shippingDetails": {"@type": "OfferShippingDetails",
"doesNotShip": True},