cnhkmcp 1.3.6__py3-none-any.whl → 1.3.8__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.
Files changed (57) hide show
  1. cnhkmcp/__init__.py +1 -1
  2. cnhkmcp/untracked/APP/.gitignore +32 -0
  3. cnhkmcp/untracked/APP/MODULAR_STRUCTURE.md +123 -0
  4. cnhkmcp/untracked/APP/README.md +309 -0
  5. cnhkmcp/untracked/APP/__pycache__/app.cpython-313.pyc +0 -0
  6. cnhkmcp/untracked/APP/blueprints/__init__.py +5 -0
  7. cnhkmcp/untracked/APP/blueprints/__pycache__/__init__.cpython-313.pyc +0 -0
  8. cnhkmcp/untracked/APP/blueprints/__pycache__/feature_engineering.cpython-313.pyc +0 -0
  9. cnhkmcp/untracked/APP/blueprints/__pycache__/idea_house.cpython-313.pyc +0 -0
  10. cnhkmcp/untracked/APP/blueprints/__pycache__/inspiration_house.cpython-313.pyc +0 -0
  11. cnhkmcp/untracked/APP/blueprints/__pycache__/paper_analysis.cpython-313.pyc +0 -0
  12. cnhkmcp/untracked/APP/blueprints/__pycache__/simulator.cpython-313.pyc +0 -0
  13. cnhkmcp/untracked/APP/blueprints/__pycache__/unified_tools.cpython-313.pyc +0 -0
  14. cnhkmcp/untracked/APP/blueprints/__pycache__/wqb_simulator.cpython-313.pyc +0 -0
  15. cnhkmcp/untracked/APP/blueprints/feature_engineering.py +347 -0
  16. cnhkmcp/untracked/APP/blueprints/idea_house.py +221 -0
  17. cnhkmcp/untracked/APP/blueprints/inspiration_house.py +432 -0
  18. cnhkmcp/untracked/APP/blueprints/paper_analysis.py +570 -0
  19. cnhkmcp/untracked/APP/custom_templates/templates.json +4582 -0
  20. cnhkmcp/untracked/APP/hkSimulator/ace_lib.py +1476 -0
  21. cnhkmcp/untracked/APP/hkSimulator/autosimulator.py +378 -0
  22. cnhkmcp/untracked/APP/hkSimulator/helpful_functions.py +180 -0
  23. cnhkmcp/untracked/APP/mirror_config.txt +20 -0
  24. cnhkmcp/untracked/APP/operaters.csv +129 -0
  25. cnhkmcp/untracked/APP/requirements.txt +44 -0
  26. cnhkmcp/untracked/APP/run_app.bat +28 -0
  27. cnhkmcp/untracked/APP/run_app.sh +34 -0
  28. cnhkmcp/untracked/APP/setup_tsinghua.bat +39 -0
  29. cnhkmcp/untracked/APP/setup_tsinghua.sh +43 -0
  30. cnhkmcp/untracked/APP/simulator/__pycache__/simulator_wqb.cpython-313.pyc +0 -0
  31. cnhkmcp/untracked/APP/simulator/alpha_submitter.py +366 -0
  32. cnhkmcp/untracked/APP/simulator/simulator_wqb.py +602 -0
  33. cnhkmcp/untracked/APP/ssrn-3332513.pdf +109188 -19
  34. cnhkmcp/untracked/APP/static/brain.js +478 -0
  35. cnhkmcp/untracked/APP/static/decoder.js +1275 -0
  36. cnhkmcp/untracked/APP/static/feature_engineering.js +1729 -0
  37. cnhkmcp/untracked/APP/static/idea_house.js +937 -0
  38. cnhkmcp/untracked/APP/static/inspiration_house.js +868 -0
  39. cnhkmcp/untracked/APP/static/paper_analysis.js +390 -0
  40. cnhkmcp/untracked/APP/static/script.js +2577 -0
  41. cnhkmcp/untracked/APP/static/simulator.js +597 -0
  42. cnhkmcp/untracked/APP/static/styles.css +3099 -0
  43. cnhkmcp/untracked/APP/templates/feature_engineering.html +959 -0
  44. cnhkmcp/untracked/APP/templates/idea_house.html +563 -0
  45. cnhkmcp/untracked/APP/templates/index.html +769 -0
  46. cnhkmcp/untracked/APP/templates/inspiration_house.html +860 -0
  47. cnhkmcp/untracked/APP/templates/paper_analysis.html +90 -0
  48. cnhkmcp/untracked/APP/templates/simulator.html +342 -0
  49. cnhkmcp/untracked/APP//321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/231/320/243/321/205/342/225/235/320/220/321/206/320/230/320/241.py +1489 -0
  50. {cnhkmcp-1.3.6.dist-info → cnhkmcp-1.3.8.dist-info}/METADATA +1 -1
  51. cnhkmcp-1.3.8.dist-info/RECORD +67 -0
  52. cnhkmcp/untracked/APP.zip +0 -0
  53. cnhkmcp-1.3.6.dist-info/RECORD +0 -20
  54. {cnhkmcp-1.3.6.dist-info → cnhkmcp-1.3.8.dist-info}/WHEEL +0 -0
  55. {cnhkmcp-1.3.6.dist-info → cnhkmcp-1.3.8.dist-info}/entry_points.txt +0 -0
  56. {cnhkmcp-1.3.6.dist-info → cnhkmcp-1.3.8.dist-info}/licenses/LICENSE +0 -0
  57. {cnhkmcp-1.3.6.dist-info → cnhkmcp-1.3.8.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,478 @@
1
+ /**
2
+ * BRAIN API Integration Module
3
+ * Handles authentication, operators, and data fields from WorldQuant BRAIN
4
+ * Now uses a local Python proxy server to bypass CORS restrictions
5
+ */
6
+
7
+ // BRAIN session and data storage
8
+ let brainSession = null;
9
+ let brainOperators = null;
10
+ let brainDataFields = null;
11
+ let brainSessionId = localStorage.getItem('brain_session_id');
12
+
13
+ // Flask app API endpoints
14
+ const PROXY_BASE = '';
15
+
16
+ // Open BRAIN login modal
17
+ function openBrainLoginModal() {
18
+ const modal = document.getElementById('brainLoginModal');
19
+ const statusDiv = document.getElementById('brainLoginStatus');
20
+ statusDiv.innerHTML = '';
21
+ statusDiv.className = 'login-status';
22
+
23
+ // Clear previous inputs
24
+ document.getElementById('brainUsername').value = '';
25
+ document.getElementById('brainPassword').value = '';
26
+
27
+ modal.style.display = 'block';
28
+ document.getElementById('brainUsername').focus();
29
+ }
30
+
31
+ // Close BRAIN login modal
32
+ function closeBrainLoginModal() {
33
+ const modal = document.getElementById('brainLoginModal');
34
+ const loginBtn = document.getElementById('loginBtn');
35
+
36
+ // Don't allow closing if login is in progress
37
+ if (loginBtn.disabled) {
38
+ return;
39
+ }
40
+
41
+ // Clean up any biometric authentication buttons
42
+ const statusDiv = document.getElementById('brainLoginStatus');
43
+ const completeBtn = statusDiv.querySelector('button');
44
+ if (completeBtn) {
45
+ completeBtn.remove();
46
+ }
47
+
48
+ modal.style.display = 'none';
49
+ }
50
+
51
+ // Authenticate with BRAIN via proxy server
52
+ async function authenticateBrain() {
53
+ const username = document.getElementById('brainUsername').value.trim();
54
+ const password = document.getElementById('brainPassword').value;
55
+ const statusDiv = document.getElementById('brainLoginStatus');
56
+ const loginBtn = document.getElementById('loginBtn');
57
+ const spinner = document.getElementById('loginSpinner');
58
+ const modal = document.getElementById('brainLoginModal');
59
+
60
+ if (!username || !password) {
61
+ showLoginStatus('Please enter both username and password.', 'error');
62
+ return;
63
+ }
64
+
65
+ // Disable all inputs and buttons
66
+ document.getElementById('brainUsername').disabled = true;
67
+ document.getElementById('brainPassword').disabled = true;
68
+ document.getElementById('cancelBtn').disabled = true;
69
+ loginBtn.disabled = true;
70
+ loginBtn.textContent = 'Connecting...';
71
+
72
+ // Show spinner
73
+ spinner.style.display = 'block';
74
+
75
+ // Disable modal closing
76
+ modal.querySelector('.close').style.display = 'none';
77
+
78
+ // Show loading state
79
+ showLoginStatus('Connecting to proxy server...', 'loading');
80
+
81
+ try {
82
+ showLoginStatus('Authenticating with BRAIN...', 'loading');
83
+
84
+ // Authenticate via proxy server
85
+ const authResponse = await fetch(`${PROXY_BASE}/api/authenticate`, {
86
+ method: 'POST',
87
+ headers: {
88
+ 'Content-Type': 'application/json'
89
+ },
90
+ body: JSON.stringify({
91
+ username: username,
92
+ password: password
93
+ })
94
+ });
95
+
96
+ const authData = await authResponse.json();
97
+
98
+ // Check if biometric authentication is required
99
+ if (authData.requires_biometric) {
100
+ showLoginStatus('Biometric authentication required. Opening BRAIN website...', 'loading');
101
+
102
+ // Open biometric URL in new tab
103
+ window.open(authData.biometric_url, '_blank');
104
+
105
+ // Store the session ID for biometric completion
106
+ brainSessionId = authData.session_id;
107
+ localStorage.setItem('brain_session_id', brainSessionId);
108
+
109
+ showLoginStatus('Please complete biometric authentication in the new tab, then click "Complete Authentication" below.', 'info');
110
+
111
+ // Show complete authentication button
112
+ const completeBtn = document.createElement('button');
113
+ completeBtn.textContent = 'Complete Authentication';
114
+ completeBtn.className = 'btn btn-secondary';
115
+ completeBtn.style.marginTop = '10px';
116
+ completeBtn.onclick = completeBiometricAuth;
117
+
118
+ const statusDiv = document.getElementById('brainLoginStatus');
119
+ statusDiv.appendChild(completeBtn);
120
+
121
+ return;
122
+ }
123
+
124
+ if (!authResponse.ok) {
125
+ throw new Error(authData.error || 'Authentication failed');
126
+ }
127
+
128
+ brainSessionId = authData.session_id;
129
+ brainSession = { authenticated: true, username: username };
130
+
131
+ // Store session ID in localStorage for other pages
132
+ localStorage.setItem('brain_session_id', brainSessionId);
133
+
134
+ // Fetch operators immediately for "Op" button functionality
135
+ showLoginStatus('Loading operators...', 'loading');
136
+ brainOperators = await getUserOperators();
137
+
138
+ // Store operators in sessionStorage for other pages (like Inspiration House)
139
+ sessionStorage.setItem('brainOperators', JSON.stringify(brainOperators));
140
+
141
+ // Update UI to show connected state
142
+ updateConnectedState();
143
+ showLoginStatus(`Successfully connected! Loaded ${brainOperators.length} operators.`, 'success');
144
+
145
+ // Disable buttons to prevent further clicks
146
+ loginBtn.disabled = true;
147
+ document.getElementById('brainUsername').disabled = true;
148
+ document.getElementById('brainPassword').disabled = true;
149
+
150
+ // Close modal after a short delay
151
+ setTimeout(() => {
152
+ // Re-enable everything before closing
153
+ document.getElementById('brainUsername').disabled = false;
154
+ document.getElementById('brainPassword').disabled = false;
155
+ document.getElementById('cancelBtn').disabled = false;
156
+ loginBtn.disabled = false;
157
+ loginBtn.textContent = 'Connect';
158
+ spinner.style.display = 'none';
159
+ modal.querySelector('.close').style.display = 'block';
160
+
161
+ closeBrainLoginModal();
162
+ }, 1500);
163
+
164
+ } catch (error) {
165
+ console.error('BRAIN authentication failed:', error);
166
+ showLoginStatus(`Connection failed: ${error.message}`, 'error');
167
+ brainSession = null;
168
+ brainSessionId = null;
169
+ } finally {
170
+ // Re-enable everything
171
+ document.getElementById('brainUsername').disabled = false;
172
+ document.getElementById('brainPassword').disabled = false;
173
+ document.getElementById('cancelBtn').disabled = false;
174
+ loginBtn.disabled = false;
175
+ loginBtn.textContent = 'Connect';
176
+ spinner.style.display = 'none';
177
+ modal.querySelector('.close').style.display = 'block';
178
+ }
179
+ }
180
+
181
+ // Complete biometric authentication
182
+ async function completeBiometricAuth() {
183
+ const statusDiv = document.getElementById('brainLoginStatus');
184
+
185
+ try {
186
+ showLoginStatus('Verifying biometric authentication...', 'loading');
187
+
188
+ const response = await fetch(`${PROXY_BASE}/api/complete-biometric`, {
189
+ method: 'POST',
190
+ headers: {
191
+ 'Session-ID': brainSessionId
192
+ }
193
+ });
194
+
195
+ const data = await response.json();
196
+
197
+ if (data.success) {
198
+ brainSessionId = data.session_id;
199
+ brainSession = { authenticated: true };
200
+ localStorage.setItem('brain_session_id', brainSessionId);
201
+
202
+ // Fetch operators
203
+ showLoginStatus('Loading operators...', 'loading');
204
+ brainOperators = await getUserOperators();
205
+
206
+ // Store operators in sessionStorage for other pages (like Inspiration House)
207
+ sessionStorage.setItem('brainOperators', JSON.stringify(brainOperators));
208
+
209
+ // Update UI
210
+ updateConnectedState();
211
+ showLoginStatus(`Successfully connected! Loaded ${brainOperators.length} operators.`, 'success');
212
+
213
+ // Close modal after delay
214
+ setTimeout(() => {
215
+ closeBrainLoginModal();
216
+ }, 1500);
217
+ } else {
218
+ showLoginStatus(`Biometric verification failed: ${data.error}`, 'error');
219
+ }
220
+
221
+ } catch (error) {
222
+ console.error('Biometric completion failed:', error);
223
+ showLoginStatus(`Biometric verification failed: ${error.message}`, 'error');
224
+ }
225
+ }
226
+
227
+ // Get user operators via proxy server
228
+ async function getUserOperators() {
229
+ if (!brainSession || !brainSessionId) {
230
+ throw new Error('Not authenticated with BRAIN');
231
+ }
232
+
233
+ try {
234
+ const response = await fetch(`${PROXY_BASE}/api/operators`, {
235
+ method: 'GET',
236
+ headers: {
237
+ 'Session-ID': brainSessionId
238
+ }
239
+ });
240
+
241
+ if (!response.ok) {
242
+ const errorData = await response.json();
243
+ throw new Error(errorData.error || 'Failed to fetch operators');
244
+ }
245
+
246
+ const operators = await response.json();
247
+ console.log(`Received ${operators.length} operators from BRAIN API`);
248
+
249
+ // Log the categories to verify we have all operator types
250
+ const categories = [...new Set(operators.map(op => op.category))].sort();
251
+ console.log(`Operator categories: ${categories.join(', ')}`);
252
+
253
+ return operators;
254
+
255
+ } catch (error) {
256
+ console.error('Failed to fetch operators:', error);
257
+ throw error;
258
+ }
259
+ }
260
+
261
+ // Get data fields via proxy server
262
+ async function getDataFields(region = 'USA', delay = 1, universe = 'TOP3000', datasetId = 'fundamental6') {
263
+ if (!brainSession || !brainSessionId) {
264
+ throw new Error('Not authenticated with BRAIN');
265
+ }
266
+
267
+ try {
268
+ const params = new URLSearchParams({
269
+ region: region,
270
+ delay: delay.toString(),
271
+ universe: universe,
272
+ dataset_id: datasetId
273
+ });
274
+
275
+ const response = await fetch(`${PROXY_BASE}/api/datafields?${params}`, {
276
+ method: 'GET',
277
+ headers: {
278
+ 'Session-ID': brainSessionId
279
+ }
280
+ });
281
+
282
+ if (!response.ok) {
283
+ const errorData = await response.json();
284
+ throw new Error(errorData.error || 'Failed to fetch data fields');
285
+ }
286
+
287
+ return await response.json();
288
+
289
+ } catch (error) {
290
+ console.error('Failed to fetch data fields:', error);
291
+ throw error;
292
+ }
293
+ }
294
+
295
+ // Update UI to show connected state
296
+ function updateConnectedState() {
297
+ // Update connect button if it exists (main page)
298
+ const connectBtn = document.getElementById('connectToBrain');
299
+ if (connectBtn) {
300
+ connectBtn.textContent = 'Connected to BRAIN';
301
+ connectBtn.className = 'btn btn-brain connected';
302
+ }
303
+
304
+ // Show connection info in the grammar errors area if it exists (main page)
305
+ const errorsDiv = document.getElementById('grammarErrors');
306
+ if (errorsDiv) {
307
+ errorsDiv.innerHTML = `<div class="success-message">
308
+ ✓ Successfully connected to WorldQuant BRAIN<br>
309
+ <strong>Username:</strong> ${brainSession.username}<br>
310
+ <strong>Operators loaded:</strong> ${brainOperators ? brainOperators.length : 0}<br>
311
+ <em>Data fields will be loaded when needed.</em>
312
+ </div>`;
313
+
314
+ // Auto-hide the message after 5 seconds
315
+ setTimeout(() => {
316
+ if (errorsDiv.innerHTML.includes('Successfully connected')) {
317
+ errorsDiv.innerHTML = '';
318
+ }
319
+ }, 5000);
320
+ }
321
+ }
322
+
323
+ // Show login status message
324
+ function showLoginStatus(message, type) {
325
+ const statusDiv = document.getElementById('brainLoginStatus');
326
+ statusDiv.textContent = message;
327
+ statusDiv.className = `login-status ${type}`;
328
+ }
329
+
330
+ // Check if connected to BRAIN
331
+ function isConnectedToBrain() {
332
+ return brainSession !== null && brainSessionId !== null;
333
+ }
334
+
335
+ // Get all available operators (fetch on-demand)
336
+ async function getAllOperators() {
337
+ if (!brainOperators && isConnectedToBrain()) {
338
+ try {
339
+ brainOperators = await getUserOperators();
340
+ // Store operators in sessionStorage for other pages (like Inspiration House)
341
+ sessionStorage.setItem('brainOperators', JSON.stringify(brainOperators));
342
+ } catch (error) {
343
+ console.error('Failed to fetch operators on-demand:', error);
344
+ return [];
345
+ }
346
+ }
347
+ return brainOperators || [];
348
+ }
349
+
350
+ // Get loaded operators synchronously (for UI components)
351
+ function getLoadedOperators() {
352
+ return brainOperators || [];
353
+ }
354
+
355
+ // Get all available data fields (fetch on-demand)
356
+ async function getAllDataFields() {
357
+ if (!brainDataFields && isConnectedToBrain()) {
358
+ try {
359
+ brainDataFields = await getDataFields();
360
+ } catch (error) {
361
+ console.error('Failed to fetch data fields on-demand:', error);
362
+ return [];
363
+ }
364
+ }
365
+ return brainDataFields || [];
366
+ }
367
+
368
+ // Get operators by category (with on-demand loading)
369
+ async function getOperatorsByCategory(category) {
370
+ const operators = await getAllOperators();
371
+ return operators.filter(op => op.category === category);
372
+ }
373
+
374
+ // Search operators (with on-demand loading)
375
+ async function searchOperators(searchTerm) {
376
+ const operators = await getAllOperators();
377
+ const term = searchTerm.toLowerCase();
378
+ return operators.filter(op =>
379
+ op.name.toLowerCase().includes(term) ||
380
+ op.category.toLowerCase().includes(term)
381
+ );
382
+ }
383
+
384
+ // Search data fields (with on-demand loading)
385
+ async function searchDataFields(searchTerm) {
386
+ const dataFields = await getAllDataFields();
387
+ const term = searchTerm.toLowerCase();
388
+ return dataFields.filter(field =>
389
+ field.id.toLowerCase().includes(term) ||
390
+ field.description.toLowerCase().includes(term)
391
+ );
392
+ }
393
+
394
+ // Logout from BRAIN
395
+ async function logoutFromBrain() {
396
+ if (brainSessionId) {
397
+ try {
398
+ await fetch(`${PROXY_BASE}/api/logout`, {
399
+ method: 'POST',
400
+ headers: {
401
+ 'Session-ID': brainSessionId
402
+ }
403
+ });
404
+ } catch (error) {
405
+ console.warn('Failed to logout from proxy server:', error);
406
+ }
407
+ }
408
+
409
+ // Clear local session data
410
+ brainSession = null;
411
+ brainSessionId = null;
412
+ brainOperators = null;
413
+ brainDataFields = null;
414
+
415
+ // Clear localStorage and sessionStorage
416
+ localStorage.removeItem('brain_session_id');
417
+ sessionStorage.removeItem('brainOperators');
418
+
419
+ // Update UI
420
+ const connectBtn = document.getElementById('connectToBrain');
421
+ if (connectBtn) {
422
+ connectBtn.textContent = 'Connect to BRAIN';
423
+ connectBtn.className = 'btn btn-brain';
424
+ }
425
+ }
426
+
427
+ // Check session validity on page load
428
+ async function checkSessionValidity() {
429
+ if (brainSessionId) {
430
+ try {
431
+ const response = await fetch(`${PROXY_BASE}/api/status`, {
432
+ method: 'GET',
433
+ headers: {
434
+ 'Session-ID': brainSessionId
435
+ }
436
+ });
437
+
438
+ if (response.ok) {
439
+ const data = await response.json();
440
+ if (data.valid) {
441
+ brainSession = { authenticated: true, username: data.username };
442
+ // Update UI to show connected state
443
+ updateConnectedState();
444
+ } else {
445
+ // Session expired, clear it
446
+ localStorage.removeItem('brain_session_id');
447
+ brainSessionId = null;
448
+ }
449
+ }
450
+ } catch (error) {
451
+ console.warn('Failed to check session validity:', error);
452
+ }
453
+ }
454
+ }
455
+
456
+ // Initialize on page load
457
+ document.addEventListener('DOMContentLoaded', checkSessionValidity);
458
+
459
+ // Export functions for use in other modules
460
+ window.brainAPI = {
461
+ openBrainLoginModal,
462
+ closeBrainLoginModal,
463
+ authenticateBrain,
464
+ isConnectedToBrain,
465
+ getAllOperators,
466
+ getAllDataFields,
467
+ getDataFields,
468
+ getOperatorsByCategory,
469
+ searchOperators,
470
+ searchDataFields,
471
+ logoutFromBrain,
472
+ getLoadedOperators
473
+ };
474
+
475
+ // Also make key functions globally available for HTML onclick handlers
476
+ window.openBrainLoginModal = openBrainLoginModal;
477
+ window.closeBrainLoginModal = closeBrainLoginModal;
478
+ window.authenticateBrain = authenticateBrain;