cnhkmcp 1.3.8__tar.gz → 1.4.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. {cnhkmcp-1.3.8/cnhkmcp.egg-info → cnhkmcp-1.4.1}/PKG-INFO +1 -1
  2. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/__init__.py +1 -1
  3. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/static/script.js +106 -4
  4. cnhkmcp-1.4.1/cnhkmcp/untracked/__pycache__/forum_functions.cpython-313.pyc +0 -0
  5. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/platform_functions.py +168 -4
  6. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked//347/244/272/344/276/213/345/267/245/344/275/234/346/265/201_daily_report_workflow.md +2 -0
  7. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1/cnhkmcp.egg-info}/PKG-INFO +1 -1
  8. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp.egg-info/SOURCES.txt +2 -1
  9. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/setup.py +1 -1
  10. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/LICENSE +0 -0
  11. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/MANIFEST.in +0 -0
  12. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/README.md +0 -0
  13. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/.gitignore +0 -0
  14. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/MODULAR_STRUCTURE.md +0 -0
  15. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/README.md +0 -0
  16. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/__pycache__/app.cpython-313.pyc +0 -0
  17. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/blueprints/__init__.py +0 -0
  18. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/blueprints/__pycache__/__init__.cpython-313.pyc +0 -0
  19. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/blueprints/__pycache__/feature_engineering.cpython-313.pyc +0 -0
  20. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/blueprints/__pycache__/idea_house.cpython-313.pyc +0 -0
  21. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/blueprints/__pycache__/inspiration_house.cpython-313.pyc +0 -0
  22. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/blueprints/__pycache__/paper_analysis.cpython-313.pyc +0 -0
  23. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/blueprints/__pycache__/simulator.cpython-313.pyc +0 -0
  24. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/blueprints/__pycache__/unified_tools.cpython-313.pyc +0 -0
  25. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/blueprints/__pycache__/wqb_simulator.cpython-313.pyc +0 -0
  26. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/blueprints/feature_engineering.py +0 -0
  27. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/blueprints/idea_house.py +0 -0
  28. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/blueprints/inspiration_house.py +0 -0
  29. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/blueprints/paper_analysis.py +0 -0
  30. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/custom_templates/templates.json +0 -0
  31. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/hkSimulator/ace_lib.py +0 -0
  32. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/hkSimulator/autosimulator.py +0 -0
  33. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/hkSimulator/helpful_functions.py +0 -0
  34. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/mirror_config.txt +0 -0
  35. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/operaters.csv +0 -0
  36. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/requirements.txt +0 -0
  37. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/run_app.bat +0 -0
  38. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/run_app.sh +0 -0
  39. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/setup_tsinghua.bat +0 -0
  40. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/setup_tsinghua.sh +0 -0
  41. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/simulator/__pycache__/simulator_wqb.cpython-313.pyc +0 -0
  42. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/simulator/alpha_submitter.py +0 -0
  43. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/simulator/simulator_wqb.py +0 -0
  44. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/ssrn-3332513.pdf +0 -0
  45. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/static/brain.js +0 -0
  46. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/static/decoder.js +0 -0
  47. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/static/feature_engineering.js +0 -0
  48. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/static/idea_house.js +0 -0
  49. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/static/inspiration_house.js +0 -0
  50. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/static/paper_analysis.js +0 -0
  51. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/static/simulator.js +0 -0
  52. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/static/styles.css +0 -0
  53. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/templates/feature_engineering.html +0 -0
  54. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/templates/idea_house.html +0 -0
  55. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/templates/index.html +0 -0
  56. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/templates/inspiration_house.html +0 -0
  57. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/templates/paper_analysis.html +0 -0
  58. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP/templates/simulator.html +0 -0
  59. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/APP//350/277/220/350/241/214/346/211/223/345/274/200/346/210/221.py" +0 -0
  60. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/arXiv_API_Tool_Manual.md +0 -0
  61. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/arxiv_api.py +0 -0
  62. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/forum_functions.py +0 -0
  63. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/sample_mcp_config.json +0 -0
  64. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked/user_config.json +0 -0
  65. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked//347/244/272/344/276/213/345/217/202/350/200/203/346/226/207/346/241/243_BRAIN_Alpha_Test_Requirements_and_Tips.md" +0 -0
  66. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked//347/244/272/344/276/213/345/267/245/344/275/234/346/265/201_Alpha_explaination_workflow.md" +0 -0
  67. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked//347/244/272/344/276/213/345/267/245/344/275/234/346/265/201_BRAIN_6_Tips_Datafield_Exploration_Guide.md" +0 -0
  68. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked//347/244/272/344/276/213/345/267/245/344/275/234/346/265/201_BRAIN_Alpha_Improvement_Workflow.md" +0 -0
  69. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp/untracked//347/244/272/344/276/213/345/267/245/344/275/234/346/265/201_Dataset_Exploration_Expert_Manual.md" +0 -0
  70. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp.egg-info/dependency_links.txt +0 -0
  71. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp.egg-info/entry_points.txt +0 -0
  72. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp.egg-info/not-zip-safe +0 -0
  73. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp.egg-info/requires.txt +0 -0
  74. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/cnhkmcp.egg-info/top_level.txt +0 -0
  75. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/requirements.txt +0 -0
  76. {cnhkmcp-1.3.8 → cnhkmcp-1.4.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cnhkmcp
3
- Version: 1.3.8
3
+ Version: 1.4.1
4
4
  Summary: A comprehensive Model Context Protocol (MCP) server for quantitative trading platform integration
5
5
  Home-page: https://github.com/cnhk/cnhkmcp
6
6
  Author: CNHK
@@ -50,7 +50,7 @@ from .untracked.forum_functions import (
50
50
  read_full_forum_post
51
51
  )
52
52
 
53
- __version__ = "1.3.8"
53
+ __version__ = "1.4.1"
54
54
  __author__ = "CNHK"
55
55
  __email__ = "cnhk@example.com"
56
56
 
@@ -1615,10 +1615,9 @@ window.onclick = function(event) {
1615
1615
  // Apply template variables
1616
1616
  function applyTemplate() {
1617
1617
  const variableInput = document.getElementById('variableInput');
1618
- const variables = variableInput.value
1619
- .split(',')
1620
- .map(v => v.trim())
1621
- .filter(v => v !== '');
1618
+
1619
+ // Special handling for bucket() functions to avoid splitting on commas inside them
1620
+ const variables = parseVariablesWithBucketSupport(variableInput.value);
1622
1621
 
1623
1622
  if (variables.length === 0) {
1624
1623
  alert('Please enter at least one variable');
@@ -1646,6 +1645,109 @@ function applyTemplate() {
1646
1645
  errorsDiv.innerHTML = `<div class="success-message">✓ Template <${currentTemplate}/> configured as ${currentConfigType} with ${variables.length} variable${variables.length > 1 ? 's' : ''}</div>`;
1647
1646
  }
1648
1647
 
1648
+ // Parse variables with special support for bucket() functions
1649
+ function parseVariablesWithBucketSupport(input) {
1650
+ const variables = [];
1651
+ let currentVariable = '';
1652
+ let i = 0;
1653
+
1654
+ while (i < input.length) {
1655
+ const char = input[i];
1656
+
1657
+ // Check if we're starting a bucket function
1658
+ if (char === 'b' && i + 7 <= input.length && input.substring(i, i + 7) === 'bucket(') {
1659
+ // Add any previous variable before the bucket function
1660
+ const trimmed = currentVariable.trim();
1661
+ if (trimmed !== '') {
1662
+ variables.push(trimmed);
1663
+ }
1664
+
1665
+ // Find the complete bucket function
1666
+ const bucketFunction = extractBucketFunction(input, i);
1667
+ if (bucketFunction) {
1668
+ // Add the complete bucket function
1669
+ variables.push(bucketFunction.function);
1670
+ currentVariable = '';
1671
+ i = bucketFunction.endIndex + 1; // Move past the bucket function
1672
+ continue;
1673
+ } else {
1674
+ currentVariable += char;
1675
+ }
1676
+ }
1677
+
1678
+ // Regular comma handling
1679
+ if (char === ',') {
1680
+ const trimmed = currentVariable.trim();
1681
+ if (trimmed !== '') {
1682
+ variables.push(trimmed);
1683
+ }
1684
+ currentVariable = '';
1685
+ } else {
1686
+ currentVariable += char;
1687
+ }
1688
+
1689
+ i++;
1690
+ }
1691
+
1692
+ // Add the last variable if there is one
1693
+ const trimmed = currentVariable.trim();
1694
+ if (trimmed !== '') {
1695
+ variables.push(trimmed);
1696
+ }
1697
+
1698
+ return variables;
1699
+ }
1700
+
1701
+ // Extract complete bucket function including all nested content
1702
+ function extractBucketFunction(input, startIndex) {
1703
+ let parenthesesCount = 0;
1704
+ let inQuotes = false;
1705
+ let quoteChar = null;
1706
+ let i = startIndex;
1707
+
1708
+ // Find the start of bucket(
1709
+ if (input.substring(i, i + 7) !== 'bucket(') {
1710
+ return null;
1711
+ }
1712
+
1713
+ parenthesesCount = 1;
1714
+ i += 7; // Move past "bucket("
1715
+
1716
+ while (i < input.length) {
1717
+ const char = input[i];
1718
+
1719
+ // Handle quotes
1720
+ if ((char === '"' || char === "'") && !inQuotes) {
1721
+ inQuotes = true;
1722
+ quoteChar = char;
1723
+ } else if (char === quoteChar && inQuotes) {
1724
+ inQuotes = false;
1725
+ quoteChar = null;
1726
+ }
1727
+
1728
+ // Only count parentheses when not inside quotes
1729
+ if (!inQuotes) {
1730
+ if (char === '(') {
1731
+ parenthesesCount++;
1732
+ } else if (char === ')') {
1733
+ parenthesesCount--;
1734
+ if (parenthesesCount === 0) {
1735
+ // Found the end of bucket function
1736
+ const functionText = input.substring(startIndex, i + 1);
1737
+ return {
1738
+ function: functionText,
1739
+ endIndex: i
1740
+ };
1741
+ }
1742
+ }
1743
+ }
1744
+
1745
+ i++;
1746
+ }
1747
+
1748
+ return null; // No matching closing parenthesis found
1749
+ }
1750
+
1649
1751
  // Clear editor
1650
1752
  function clearEditor() {
1651
1753
  const editor = document.getElementById('expressionEditor');
@@ -13,6 +13,7 @@ from dataclasses import dataclass, asdict
13
13
  from datetime import datetime, timedelta
14
14
  import os
15
15
  import sys
16
+ import math
16
17
  from time import sleep
17
18
 
18
19
  import requests
@@ -371,6 +372,34 @@ class BrainApiClient:
371
372
  except Exception as e:
372
373
  self.log(f"Failed to get alpha details: {str(e)}", "ERROR")
373
374
  raise
375
+
376
+ def _is_atom(self, detail: Optional[Dict[str, Any]]) -> bool:
377
+ """Match atom detection used in extract_regular_alphas.py:
378
+ - Primary signal: 'classifications' entries containing 'SINGLE_DATA_SET'
379
+ - Fallbacks: tags list contains 'atom' or classification id/name contains 'ATOM'
380
+ """
381
+ if not detail or not isinstance(detail, dict):
382
+ return False
383
+
384
+ classifications = detail.get('classifications') or []
385
+ for c in classifications:
386
+ cid = (c.get('id') or c.get('name') or '')
387
+ if isinstance(cid, str) and 'SINGLE_DATA_SET' in cid:
388
+ return True
389
+
390
+ # Fallbacks
391
+ tags = detail.get('tags') or []
392
+ if isinstance(tags, list):
393
+ for t in tags:
394
+ if isinstance(t, str) and t.strip().lower() == 'atom':
395
+ return True
396
+
397
+ for c in classifications:
398
+ cid = (c.get('id') or c.get('name') or '')
399
+ if isinstance(cid, str) and 'ATOM' in cid.upper():
400
+ return True
401
+
402
+ return False
374
403
 
375
404
  async def get_datasets(self, instrument_type: str = "EQUITY", region: str = "USA",
376
405
  delay: int = 1, universe: str = "TOP3000", theme: str = "false", search: Optional[str] = None) -> Dict[str, Any]:
@@ -1165,6 +1194,122 @@ class BrainApiClient:
1165
1194
  self.log(f"Failed to get pyramid multipliers: {str(e)}", "ERROR")
1166
1195
  raise
1167
1196
 
1197
+ async def value_factor_trendScore(self, start_date: str, end_date: str) -> Dict[str, Any]:
1198
+ """Compute diversity score for regular alphas in a date range.
1199
+
1200
+ Description:
1201
+ This function calculate the diversity of the users' submission, by checking the diversity, we can have a good understanding on the valuefactor's trend.
1202
+ value factor of a user is defiend by This diversity score, which measures three key aspects of work output: the proportion of works
1203
+ with the "Atom" tag (S_A), atom proportion, the breadth of pyramids covered (S_P), and how evenly works
1204
+ are distributed across those pyramids (S_H). Calculated as their product, it rewards
1205
+ strong performance across all three dimensions—encouraging more Atom-tagged works,
1206
+ wider pyramid coverage, and balanced distribution—with weaknesses in any area lowering
1207
+ the total score significantly.
1208
+
1209
+ Inputs (hints for AI callers):
1210
+ - start_date (str): ISO UTC start datetime, e.g. '2025-08-14T00:00:00Z'
1211
+ - end_date (str): ISO UTC end datetime, e.g. '2025-08-18T23:59:59Z'
1212
+ - Note: this tool always uses 'OS' (submission dates) to define the window; callers do not need to supply a stage.
1213
+ - Note: P_max (total number of possible pyramids) is derived from the platform
1214
+ pyramid-multipliers endpoint and not supplied by callers.
1215
+
1216
+ Returns (compact JSON): {
1217
+ 'diversity_score': float,
1218
+ 'N': int, # total regular alphas in window
1219
+ 'A': int, # number of Atom-tagged works (is_single_data_set)
1220
+ 'P': int, # pyramid coverage count in the sample
1221
+ 'P_max': int, # used max for normalization
1222
+ 'S_A': float, 'S_P': float, 'S_H': float,
1223
+ 'per_pyramid_counts': {pyramid_name: count}
1224
+ }
1225
+ """
1226
+ # Fetch user alphas (always use OS / submission dates per product policy)
1227
+ await self.ensure_authenticated()
1228
+ alphas_resp = await self.get_user_alphas(stage='OS', limit=500, submission_start_date=start_date, submission_end_date=end_date)
1229
+
1230
+ if not isinstance(alphas_resp, dict) or 'results' not in alphas_resp:
1231
+ return {'error': 'Unexpected response from get_user_alphas', 'raw': alphas_resp}
1232
+
1233
+ alphas = alphas_resp['results']
1234
+ regular = [a for a in alphas if a.get('type') == 'REGULAR']
1235
+
1236
+ # Fetch details for each regular alpha
1237
+ pyramid_list = []
1238
+ atom_count = 0
1239
+ per_pyramid = {}
1240
+ for a in regular:
1241
+ try:
1242
+ detail = await self.get_alpha_details(a.get('id'))
1243
+ except Exception:
1244
+ continue
1245
+
1246
+ is_atom = self._is_atom(detail)
1247
+ if is_atom:
1248
+ atom_count += 1
1249
+
1250
+ # Extract pyramids
1251
+ ps = []
1252
+ if isinstance(detail.get('pyramids'), list):
1253
+ ps = [p.get('name') for p in detail.get('pyramids') if p.get('name')]
1254
+ else:
1255
+ pt = detail.get('pyramidThemes') or {}
1256
+ pss = pt.get('pyramids') if isinstance(pt, dict) else None
1257
+ if pss and isinstance(pss, list):
1258
+ ps = [p.get('name') for p in pss if p.get('name')]
1259
+
1260
+ for p in ps:
1261
+ pyramid_list.append(p)
1262
+ per_pyramid[p] = per_pyramid.get(p, 0) + 1
1263
+
1264
+ N = len(regular)
1265
+ A = atom_count
1266
+ P = len(per_pyramid)
1267
+
1268
+ # Determine P_max similarly to the script: use pyramid multipliers if available
1269
+ P_max = None
1270
+ try:
1271
+ pm = await self.get_pyramid_multipliers()
1272
+ if isinstance(pm, dict) and 'pyramids' in pm:
1273
+ pyramids_list = pm.get('pyramids') or []
1274
+ P_max = len(pyramids_list)
1275
+ except Exception:
1276
+ P_max = None
1277
+
1278
+ if not P_max or P_max <= 0:
1279
+ P_max = max(P, 1)
1280
+
1281
+ # Component scores
1282
+ S_A = (A / N) if N > 0 else 0.0
1283
+ S_P = (P / P_max) if P_max > 0 else 0.0
1284
+
1285
+ # Entropy
1286
+ S_H = 0.0
1287
+ if P <= 1 or not per_pyramid:
1288
+ S_H = 0.0
1289
+ else:
1290
+ total_occ = sum(per_pyramid.values())
1291
+ H = 0.0
1292
+ for cnt in per_pyramid.values():
1293
+ q = cnt / total_occ if total_occ > 0 else 0
1294
+ if q > 0:
1295
+ H -= q * math.log2(q)
1296
+ max_H = math.log2(P) if P > 0 else 1
1297
+ S_H = (H / max_H) if max_H > 0 else 0.0
1298
+
1299
+ diversity_score = S_A * S_P * S_H
1300
+
1301
+ return {
1302
+ 'diversity_score': diversity_score,
1303
+ 'N': N,
1304
+ 'A': A,
1305
+ 'P': P,
1306
+ 'P_max': P_max,
1307
+ 'S_A': S_A,
1308
+ 'S_P': S_P,
1309
+ 'S_H': S_H,
1310
+ 'per_pyramid_counts': per_pyramid
1311
+ }
1312
+
1168
1313
  async def get_pyramid_alphas(self, start_date: Optional[str] = None,
1169
1314
  end_date: Optional[str] = None) -> Dict[str, Any]:
1170
1315
  """Get user's current alpha distribution across pyramid categories."""
@@ -1514,6 +1659,25 @@ async def authenticate(email: Optional[str] = "", password: Optional[str] = "")
1514
1659
  except Exception as e:
1515
1660
  return {"error": str(e)}
1516
1661
 
1662
+
1663
+ @mcp.tool()
1664
+ async def value_factor_trendScore(start_date: str, end_date: str) -> Dict[str, Any]:
1665
+ """Compute and return the diversity score for REGULAR alphas in a submission-date window.
1666
+ This function calculate the diversity of the users' submission, by checking the diversity, we can have a good understanding on the valuefactor's trend.
1667
+ This MCP tool wraps BrainApiClient.value_factor_trendScore and always uses submission dates (OS).
1668
+
1669
+ Inputs:
1670
+ - start_date: ISO UTC start datetime (e.g. '2025-08-14T00:00:00Z')
1671
+ - end_date: ISO UTC end datetime (e.g. '2025-08-18T23:59:59Z')
1672
+ - p_max: optional integer total number of pyramid categories for normalization
1673
+
1674
+ Returns: compact JSON with diversity_score, N, A, P, P_max, S_A, S_P, S_H, per_pyramid_counts
1675
+ """
1676
+ try:
1677
+ return await brain_client.value_factor_trendScore(start_date=start_date, end_date=end_date)
1678
+ except Exception as e:
1679
+ return {"error": str(e)}
1680
+
1517
1681
  @mcp.tool()
1518
1682
  async def manage_config(action: str = "get", settings: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
1519
1683
  """
@@ -2284,7 +2448,7 @@ async def read_specific_documentation(page_id: str) -> Dict[str, Any]:
2284
2448
  # Badge status MCP tool removed as requested
2285
2449
 
2286
2450
  @mcp.tool()
2287
- async def create_multi_regularAlpha_simulation(
2451
+ async def create_multiSim(
2288
2452
  alpha_expressions: List[str],
2289
2453
  instrument_type: str = "EQUITY",
2290
2454
  region: str = "USA",
@@ -2574,10 +2738,10 @@ async def get_daily_and_quarterly_payment(email: str = "", password: str = "") -
2574
2738
 
2575
2739
 
2576
2740
 
2577
- # New MCP tool: get_error_message_fromAlphaLocation
2741
+ # New MCP tool: get_SimError_detail
2578
2742
  from typing import Sequence
2579
2743
  @mcp.tool()
2580
- async def get_error_message_fromAlphaLocation(locations: Sequence[str]) -> dict:
2744
+ async def get_SimError_detail(locations: Sequence[str]) -> dict:
2581
2745
  """
2582
2746
  Fetch and parse error/status from multiple simulation locations (URLs).
2583
2747
  Args:
@@ -2616,6 +2780,6 @@ async def get_error_message_fromAlphaLocation(locations: Sequence[str]) -> dict:
2616
2780
  return {"results": results}
2617
2781
 
2618
2782
  if __name__ == "__main__":
2619
- print("🧠 WorldQuant BRAIN MCP Server Starting...", file=sys.stderr)
2783
+ print("WorldQuant BRAIN MCP Server Starting...", file=sys.stderr)
2620
2784
  mcp.run()
2621
2785
 
@@ -34,9 +34,11 @@
34
34
  2. **社区动态**:从消息中提取社区相关信息,如研究论文或热门话题。
35
35
  3. **排行榜变化**:记录用户位置变化。
36
36
  - 使用工具:`mcp_brain-api_get_leaderboard`(设置 `user_id` 为用户 ID,如 "CQ89422")。
37
+ 4. **多样性分数**:收集用户最近一个季度的多样性分数,获知其value factor趋势,该分数捕捉用户提交Alpha的多样性,来判断其value factor的变化趋势,在0-1之间,越高越好,据此提出具体建议。
37
38
  - **使用的 MCP 工具**:
38
39
  - `mcp_brain-api_get_messages`:获取平台公告和社区动态。
39
40
  - `mcp_brain-api_get_leaderboard`:获取用户排行榜统计。
41
+ - `mcp_brain-api_value_factor_trendScore`:用户value factor趋势,又名多样性分数。
40
42
 
41
43
  ### 3. 比赛参与与进度
42
44
  - **步骤**:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cnhkmcp
3
- Version: 1.3.8
3
+ Version: 1.4.1
4
4
  Summary: A comprehensive Model Context Protocol (MCP) server for quantitative trading platform integration
5
5
  Home-page: https://github.com/cnhk/cnhkmcp
6
6
  Author: CNHK
@@ -70,4 +70,5 @@ cnhkmcp/untracked/APP/templates/idea_house.html
70
70
  cnhkmcp/untracked/APP/templates/index.html
71
71
  cnhkmcp/untracked/APP/templates/inspiration_house.html
72
72
  cnhkmcp/untracked/APP/templates/paper_analysis.html
73
- cnhkmcp/untracked/APP/templates/simulator.html
73
+ cnhkmcp/untracked/APP/templates/simulator.html
74
+ cnhkmcp/untracked/__pycache__/forum_functions.cpython-313.pyc
@@ -13,7 +13,7 @@ def read_requirements():
13
13
 
14
14
  setup(
15
15
  name="cnhkmcp",
16
- version="1.3.8",
16
+ version="1.4.1",
17
17
  author="CNHK",
18
18
  author_email="cnhk@example.com",
19
19
  description="A comprehensive Model Context Protocol (MCP) server for quantitative trading platform integration",
File without changes
File without changes
File without changes
File without changes
File without changes