This repository was archived by the owner on Jul 22, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfactsheet.py
More file actions
105 lines (74 loc) · 2.48 KB
/
Copy pathfactsheet.py
File metadata and controls
105 lines (74 loc) · 2.48 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
"""Pydantic factsheet schema for HKEX IPO filings.
Grounded in HKEX Guidance Letter GL56-13 (Guide for New Listing Applicants,
Jan 2024). One schema spans Application Proof -> PHIP -> Prospectus; per-field
status carries the stage-dependent completeness.
"""
from __future__ import annotations
from enum import StrEnum
from pydantic import BaseModel, model_validator
SCHEMA_VERSION = "202401"
class FieldStatus(StrEnum):
DISCLOSED = "disclosed"
PENDING = "pending"
REDACTED = "redacted"
OMITTED = "omitted"
NOT_APPLICABLE = "not_applicable"
class Citation(BaseModel):
page: int # 1-indexed page in the source PDF
quote: str | None = None
class Field[T](BaseModel):
"""A single extractable leaf: a value plus its disclosure status + sources."""
value: T | None = None
status: FieldStatus
citations: list[Citation] = []
raw_text: str | None = None
@model_validator(mode="after")
def _disclosed_needs_citation(self) -> Field[T]:
if self.status == FieldStatus.DISCLOSED and not self.citations:
raise ValueError("a DISCLOSED field must carry at least one citation")
return self
class DocumentType(StrEnum):
APPLICATION_PROOF = "application_proof"
PHIP = "phip"
PROSPECTUS = "prospectus"
class DocumentMeta(BaseModel):
title: str
issuer: str
stock_code: Field[str]
doc_type: DocumentType
currency: Field[str]
source_url: str
sha256: str
page_count: int
class FinancialMetric(BaseModel):
metric: str
period: str
value: Field[float]
unit: str
class RiskFactor(BaseModel):
claim: Field[str]
severity: str # high | medium | low
class UseOfProceedsItem(BaseModel):
purpose: str
pct: Field[float]
amount: Field[float]
class TimetableEvent(BaseModel):
event: str
date: Field[str]
def _redacted_field() -> Field:
return Field(value=None, status=FieldStatus.REDACTED)
class OfferTerms(BaseModel):
price_range: Field[dict] = _redacted_field()
num_offer_shares: Field[float] = _redacted_field()
offer_size_value: Field[float] = _redacted_field()
use_of_proceeds: list[UseOfProceedsItem] = []
cornerstones: list[Field[str]] = []
timetable: list[TimetableEvent] = []
syndicate: list[Field[str]] = []
class Factsheet(BaseModel):
schema_version: str = SCHEMA_VERSION
stage: DocumentType
document: DocumentMeta
financial_highlights: list[FinancialMetric]
risks: list[RiskFactor]
offer_terms: OfferTerms