CiscsoPonce commited on
Commit
73d6dae
·
1 Parent(s): bfab9f9

fix: Kelly per-verdict caps, more noise words, higher token limit, Pydantic warning

Browse files

- Cap Kelly per verdict: STRONG BUY 25%, BUY 15%, WATCH 5% (was flat 25%)
- Cap raw Kelly fraction at 0.5 to prevent extreme values from small avg_loss
- Add THING, TXTW, MRC, HERE and 20+ more common words to noise filter
- Increase structured output max_tokens from 8192 to 16384
- Fix Pydantic warning filter to match by module instead of message string

Made-with: Cursor

src/agent.py CHANGED
@@ -375,7 +375,7 @@ def analyst_node(state):
375
 
376
  structured_llm = get_structured_llm().with_structured_output(InvestmentVerdict)
377
  with warnings.catch_warnings():
378
- warnings.filterwarnings("ignore", message="Pydantic serializer warnings")
379
  result = structured_llm.invoke(prompt)
380
 
381
  stats = get_kelly_stats()
 
375
 
376
  structured_llm = get_structured_llm().with_structured_output(InvestmentVerdict)
377
  with warnings.catch_warnings():
378
+ warnings.filterwarnings("ignore", category=UserWarning, module="pydantic")
379
  result = structured_llm.invoke(prompt)
380
 
381
  stats = get_kelly_stats()
src/core/ticker_utils.py CHANGED
@@ -42,6 +42,10 @@ NOISE_WORDS = frozenset({
42
  "SPAC", "NBER", "OPEC", "MSCI", "EMEA", "APAC", "OECD", "FIFO",
43
  "FINRA", "SIPC", "FDIC", "LISA", "ISA", "ATM", "AMA", "FDA",
44
  "PHNX", "IPG", "GAAP", "IFRS", "FASB", "IASB", "PCAOB",
 
 
 
 
45
  })
46
 
47
  _MAX_TICKER_LEN = 8 # longest valid ticker with suffix: e.g. CHE.UN.TO
 
42
  "SPAC", "NBER", "OPEC", "MSCI", "EMEA", "APAC", "OECD", "FIFO",
43
  "FINRA", "SIPC", "FDIC", "LISA", "ISA", "ATM", "AMA", "FDA",
44
  "PHNX", "IPG", "GAAP", "IFRS", "FASB", "IASB", "PCAOB",
45
+ "THING", "TXTW", "MRC", "HERE", "ELSE", "SURE", "WORK",
46
+ "SAFE", "IDEA", "PLAN", "RULE", "STEP", "PLAY", "OPEN",
47
+ "PART", "NOTE", "LINE", "READ", "FILL", "SIZE", "WIDE",
48
+ "SIGN", "RISE", "LEAD", "PUSH", "PULL", "DROP", "JUMP",
49
  })
50
 
51
  _MAX_TICKER_LEN = 8 # longest valid ticker with suffix: e.g. CHE.UN.TO
src/llm.py CHANGED
@@ -48,7 +48,7 @@ def get_llm() -> ChatOpenAI:
48
  return _llm_instance
49
 
50
 
51
- def get_structured_llm(max_tokens: int = 8192) -> ChatOpenAI:
52
  """Return an LLM instance configured for structured output.
53
 
54
  Uses a capped ``max_tokens`` to prevent reasoning models from
 
48
  return _llm_instance
49
 
50
 
51
+ def get_structured_llm(max_tokens: int = 16384) -> ChatOpenAI:
52
  """Return an LLM instance configured for structured output.
53
 
54
  Uses a capped ``max_tokens`` to prevent reasoning models from
src/models/kelly.py CHANGED
@@ -34,6 +34,12 @@ _VERDICT_SCALE = {
34
  }
35
  _POS_FLOOR = 1.0
36
  _POS_CAP = 25.0
 
 
 
 
 
 
37
 
38
 
39
  @dataclass
@@ -160,7 +166,7 @@ def get_kelly_stats() -> KellyStats:
160
  else:
161
  kelly = 0.0
162
 
163
- kelly = max(kelly, 0.0)
164
 
165
  result = KellyStats(
166
  total_trades=total,
@@ -201,5 +207,6 @@ def calculate_position_size(stats: KellyStats, verdict: str) -> float:
201
  return 0.0
202
 
203
  raw = stats.half_kelly * scale * 100
 
204
 
205
- return round(max(_POS_FLOOR, min(raw, _POS_CAP)), 1)
 
34
  }
35
  _POS_FLOOR = 1.0
36
  _POS_CAP = 25.0
37
+ _VERDICT_CAPS = {
38
+ "STRONG BUY": 25.0,
39
+ "BUY": 15.0,
40
+ "WATCH": 5.0,
41
+ }
42
+ _MAX_KELLY_FRACTION = 0.5 # cap raw Kelly to avoid extreme values
43
 
44
 
45
  @dataclass
 
166
  else:
167
  kelly = 0.0
168
 
169
+ kelly = max(min(kelly, _MAX_KELLY_FRACTION), 0.0)
170
 
171
  result = KellyStats(
172
  total_trades=total,
 
207
  return 0.0
208
 
209
  raw = stats.half_kelly * scale * 100
210
+ cap = _VERDICT_CAPS.get(verdict, _POS_CAP)
211
 
212
+ return round(max(_POS_FLOOR, min(raw, cap)), 1)
src/whale_hunter.py CHANGED
@@ -313,7 +313,7 @@ def analyst_node(state):
313
 
314
  structured_llm = get_structured_llm().with_structured_output(InvestmentVerdict)
315
  with warnings.catch_warnings():
316
- warnings.filterwarnings("ignore", message="Pydantic serializer warnings")
317
  result = structured_llm.invoke(prompt)
318
 
319
  stats = get_kelly_stats()
 
313
 
314
  structured_llm = get_structured_llm().with_structured_output(InvestmentVerdict)
315
  with warnings.catch_warnings():
316
+ warnings.filterwarnings("ignore", category=UserWarning, module="pydantic")
317
  result = structured_llm.invoke(prompt)
318
 
319
  stats = get_kelly_stats()