cnhkmcp 1.2.1__py3-none-any.whl → 1.2.2__py3-none-any.whl

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.
cnhkmcp/__init__.py CHANGED
@@ -50,7 +50,7 @@ from .untracked.forum_functions import (
50
50
  read_full_forum_post
51
51
  )
52
52
 
53
- __version__ = "1.2.1"
53
+ __version__ = "1.2.2"
54
54
  __author__ = "CNHK"
55
55
  __email__ = "cnhk@example.com"
56
56
 
@@ -389,7 +389,7 @@ class BrainApiClient:
389
389
  response = self.session.get(f"{self.base_url}/data-sets", params=params)
390
390
  response.raise_for_status()
391
391
  response = response.json()
392
- response['extraNote'] = "if your returned result is 0, you may want to check your parameter by using get_instrument_options tool to got correct parameter"
392
+ response['extraNote'] = "if your returned result is 0, you may want to check your parameter by using get_platform_setting_options tool to got correct parameter"
393
393
  return response
394
394
  except Exception as e:
395
395
  self.log(f"Failed to get datasets: {str(e)}", "ERROR")
@@ -423,7 +423,7 @@ class BrainApiClient:
423
423
  response = self.session.get(f"{self.base_url}/data-fields", params=params)
424
424
  response.raise_for_status()
425
425
  response = response.json()
426
- response['extraNote'] = "if your returned result is 0, you may want to check your parameter by using get_instrument_options tool to got correct parameter"
426
+ response['extraNote'] = "if your returned result is 0, you may want to check your parameter by using get_platform_setting_options tool to got correct parameter"
427
427
  return response
428
428
  except Exception as e:
429
429
  self.log(f"Failed to get datafields: {str(e)}", "ERROR")
@@ -1062,7 +1062,7 @@ class BrainApiClient:
1062
1062
  self.log(f"Failed to get competition agreement: {str(e)}", "ERROR")
1063
1063
  raise
1064
1064
 
1065
- async def get_instrument_options(self) -> Dict[str, Any]:
1065
+ async def get_platform_setting_options(self) -> Dict[str, Any]:
1066
1066
  """Get available instrument types, regions, delays, and universes."""
1067
1067
  await self.ensure_authenticated()
1068
1068
 
@@ -1212,14 +1212,54 @@ brain_client = BrainApiClient()
1212
1212
  # Configuration management
1213
1213
  CONFIG_FILE = "user_config.json"
1214
1214
 
1215
+ def _resolve_config_path(for_write: bool = False) -> str:
1216
+ """Resolve the absolute path to the config file.
1217
+
1218
+ Resolution order:
1219
+ 1) BRAIN_CONFIG_PATH env var (explicit file path)
1220
+ 2) File in the same directory as this Python module
1221
+ 3) Current working directory (read fallback only)
1222
+
1223
+ When for_write is True, prefers module directory (or env path) and will
1224
+ return that even if it doesn't exist yet.
1225
+ """
1226
+ try:
1227
+ # 1) Explicit override
1228
+ env_path = os.environ.get("BRAIN_CONFIG_PATH")
1229
+ if env_path:
1230
+ return os.path.abspath(env_path)
1231
+
1232
+ # 2) Same directory as this .py module
1233
+ module_dir = os.path.dirname(os.path.abspath(__file__))
1234
+ module_path = os.path.join(module_dir, CONFIG_FILE)
1235
+ if not for_write and os.path.exists(module_path):
1236
+ return module_path
1237
+
1238
+ # 3) Fallback to CWD for backward compatibility (read-only preference)
1239
+ cwd_path = os.path.abspath(CONFIG_FILE)
1240
+ if not for_write and os.path.exists(cwd_path):
1241
+ return cwd_path
1242
+
1243
+ # For writes (or when nothing exists), prefer the module directory
1244
+ return module_path
1245
+ except Exception as e:
1246
+ # As a last resort, use the bare filename in CWD
1247
+ logger.error(f"Failed to resolve config path, defaulting to CWD: {e}")
1248
+ return os.path.abspath(CONFIG_FILE)
1249
+
1215
1250
  def load_config() -> Dict[str, Any]:
1216
- """Load configuration from file."""
1217
- if os.path.exists(CONFIG_FILE):
1251
+ """Load configuration from file with robust path resolution.
1252
+
1253
+ Looks for the config in this order: BRAIN_CONFIG_PATH -> module directory -> CWD.
1254
+ Returns an empty dict when not found or on error.
1255
+ """
1256
+ path = _resolve_config_path(for_write=False)
1257
+ if os.path.exists(path):
1218
1258
  try:
1219
- with open(CONFIG_FILE, 'r') as f:
1259
+ with open(path, 'r', encoding='utf-8') as f:
1220
1260
  return json.load(f)
1221
1261
  except Exception as e:
1222
- logger.error(f"Failed to load config: {e}")
1262
+ logger.error(f"Failed to load config from '{path}': {e}")
1223
1263
  return {}
1224
1264
 
1225
1265
  def load_brain_credentials() -> Optional[tuple]:
@@ -1237,10 +1277,16 @@ def load_brain_credentials() -> Optional[tuple]:
1237
1277
  return None
1238
1278
 
1239
1279
  def save_config(config: Dict[str, Any]):
1240
- """Save configuration to file."""
1280
+ """Save configuration to file using the resolved config path.
1281
+
1282
+ Uses BRAIN_CONFIG_PATH if set; otherwise writes next to this module.
1283
+ Ensures the target directory exists.
1284
+ """
1241
1285
  try:
1242
- with open(CONFIG_FILE, 'w') as f:
1243
- json.dump(config, f, indent=2)
1286
+ path = _resolve_config_path(for_write=True)
1287
+ os.makedirs(os.path.dirname(path), exist_ok=True)
1288
+ with open(path, 'w', encoding='utf-8') as f:
1289
+ json.dump(config, f, indent=2, ensure_ascii=False)
1244
1290
  except Exception as e:
1245
1291
  logger.error(f"Failed to save config: {e}")
1246
1292
 
@@ -1946,10 +1992,18 @@ async def get_competition_agreement(competition_id: str) -> Dict[str, Any]:
1946
1992
  return {"error": str(e)}
1947
1993
 
1948
1994
  @mcp.tool()
1949
- async def get_instrument_options() -> Dict[str, Any]:
1950
- """Get available instrument types, regions, delays, and universes."""
1995
+ async def get_platform_setting_options() -> Dict[str, Any]:
1996
+ """Discover valid simulation setting options (instrument types, regions, delays, universes, neutralization).
1997
+
1998
+ Use this when a simulation request might contain an invalid/mismatched setting. If an AI or user supplies
1999
+ incorrect parameters (e.g., wrong region for an instrument type), call this tool to retrieve the authoritative
2000
+ option sets and correct the inputs before proceeding.
2001
+
2002
+ Returns:
2003
+ A structured list of valid combinations and choice lists to validate or fix simulation settings.
2004
+ """
1951
2005
  try:
1952
- return await brain_client.get_instrument_options()
2006
+ return await brain_client.get_platform_setting_options()
1953
2007
  except Exception as e:
1954
2008
  return {"error": str(e)}
1955
2009
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cnhkmcp
3
- Version: 1.2.1
3
+ Version: 1.2.2
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
@@ -0,0 +1,10 @@
1
+ cnhkmcp/__init__.py,sha256=jLSpv4B0gds0czwoFi1w5-qZBViB9f8yUZN4_9U1yf8,2758
2
+ cnhkmcp/untracked/forum_functions.py,sha256=78wzvN_UYWwbWU40q8_FJNSFPJnND6W9ZRey6MSSiEk,45516
3
+ cnhkmcp/untracked/platform_functions.py,sha256=7Vnul6prlHwCNB0L0X_sLwR_-C53y1sKDhAKF6KOE1A,82452
4
+ cnhkmcp/untracked/user_config.json,sha256=_INn1X1qIsITrmEno-BRlQOAGm9wnNCw-6B333DEvnk,695
5
+ cnhkmcp-1.2.2.dist-info/licenses/LICENSE,sha256=QLxO2eNMnJQEdI_R1UV2AOD-IvuA8zVrkHWA4D9gtoc,1081
6
+ cnhkmcp-1.2.2.dist-info/METADATA,sha256=xAuZdgGb0hWe_FmVuTT0JTVwjb3tstKBcyerAlr8rMI,5171
7
+ cnhkmcp-1.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
+ cnhkmcp-1.2.2.dist-info/entry_points.txt,sha256=lTQieVyIvjhSMK4fT-XwnccY-JBC1H4vVQ3V9dDM-Pc,70
9
+ cnhkmcp-1.2.2.dist-info/top_level.txt,sha256=x--ibUcSgOS9Z_RWK2Qc-vfs7DaXQN-WMaaxEETJ1Bw,8
10
+ cnhkmcp-1.2.2.dist-info/RECORD,,
@@ -1,10 +0,0 @@
1
- cnhkmcp/__init__.py,sha256=P9ZwPprkFWPMsX6zdprKviA-9LODjQ-eocdzhLiZNkg,2758
2
- cnhkmcp/untracked/forum_functions.py,sha256=78wzvN_UYWwbWU40q8_FJNSFPJnND6W9ZRey6MSSiEk,45516
3
- cnhkmcp/untracked/platform_functions.py,sha256=LQ0s1dASC_2KoZ5XhRf4G2mRZERMN2bScOklnRVyfdQ,80066
4
- cnhkmcp/untracked/user_config.json,sha256=_INn1X1qIsITrmEno-BRlQOAGm9wnNCw-6B333DEvnk,695
5
- cnhkmcp-1.2.1.dist-info/licenses/LICENSE,sha256=QLxO2eNMnJQEdI_R1UV2AOD-IvuA8zVrkHWA4D9gtoc,1081
6
- cnhkmcp-1.2.1.dist-info/METADATA,sha256=D1f88diDrbkAj8XrL0aGTodOl74L5KzIY-5XvEPfbkE,5171
7
- cnhkmcp-1.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
- cnhkmcp-1.2.1.dist-info/entry_points.txt,sha256=lTQieVyIvjhSMK4fT-XwnccY-JBC1H4vVQ3V9dDM-Pc,70
9
- cnhkmcp-1.2.1.dist-info/top_level.txt,sha256=x--ibUcSgOS9Z_RWK2Qc-vfs7DaXQN-WMaaxEETJ1Bw,8
10
- cnhkmcp-1.2.1.dist-info/RECORD,,