bulltrackers-module 1.0.716 → 1.0.717
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.
|
@@ -185,6 +185,12 @@ async function commitResults(stateObj, dStr, passName, config, deps, skipStatusW
|
|
|
185
185
|
|
|
186
186
|
runMetrics.io.writes += 1;
|
|
187
187
|
|
|
188
|
+
// 4. Write to BigQuery (for analytics) - same structure as other computations
|
|
189
|
+
// Page computations store the full result object { cid1: {...}, cid2: {...}, ... } in result_data
|
|
190
|
+
await writeToBigQuery(result, name, dStr, calc.manifest.category, logger, false).catch(err => {
|
|
191
|
+
logger.log('WARN', `[BigQuery] Failed to write page computation ${name} for ${dStr}: ${err.message}`);
|
|
192
|
+
});
|
|
193
|
+
|
|
188
194
|
if (isFinalFlush && calc.manifest.hash) {
|
|
189
195
|
successUpdates[name] = {
|
|
190
196
|
hash: calc.manifest.hash, simHash: simHash, resultHash: resultHash,
|
|
@@ -625,6 +625,11 @@ const SCHEMAS = {
|
|
|
625
625
|
{ name: 'instrument_id', type: 'INT64', mode: 'REQUIRED' },
|
|
626
626
|
{ name: 'insights_data', type: 'JSON', mode: 'REQUIRED' },
|
|
627
627
|
{ name: 'fetched_at', type: 'TIMESTAMP', mode: 'REQUIRED' }
|
|
628
|
+
],
|
|
629
|
+
ticker_mappings: [
|
|
630
|
+
{ name: 'instrument_id', type: 'INT64', mode: 'REQUIRED' },
|
|
631
|
+
{ name: 'ticker', type: 'STRING', mode: 'REQUIRED' },
|
|
632
|
+
{ name: 'last_updated', type: 'TIMESTAMP', mode: 'REQUIRED' }
|
|
628
633
|
]
|
|
629
634
|
};
|
|
630
635
|
|
|
@@ -812,6 +817,27 @@ async function ensureInstrumentInsightsTable(logger = null) {
|
|
|
812
817
|
);
|
|
813
818
|
}
|
|
814
819
|
|
|
820
|
+
/**
|
|
821
|
+
* Ensure ticker_mappings table exists
|
|
822
|
+
* @param {object} logger - Logger instance
|
|
823
|
+
* @returns {Promise<Table>}
|
|
824
|
+
*/
|
|
825
|
+
async function ensureTickerMappingsTable(logger = null) {
|
|
826
|
+
const datasetId = process.env.BIGQUERY_DATASET_ID || 'bulltrackers_data';
|
|
827
|
+
const tableId = 'ticker_mappings';
|
|
828
|
+
const schema = getSchema(tableId);
|
|
829
|
+
|
|
830
|
+
return await ensureTableExists(
|
|
831
|
+
datasetId,
|
|
832
|
+
tableId,
|
|
833
|
+
schema,
|
|
834
|
+
{
|
|
835
|
+
clusterFields: ['instrument_id']
|
|
836
|
+
},
|
|
837
|
+
logger
|
|
838
|
+
);
|
|
839
|
+
}
|
|
840
|
+
|
|
815
841
|
/**
|
|
816
842
|
* Query portfolio data from BigQuery
|
|
817
843
|
* @param {string} dateStr - Date string (YYYY-MM-DD)
|
|
@@ -1631,6 +1657,60 @@ async function queryAssetPrices(startDateStr = null, endDateStr = null, instrume
|
|
|
1631
1657
|
}
|
|
1632
1658
|
}
|
|
1633
1659
|
|
|
1660
|
+
/**
|
|
1661
|
+
* Query ticker mappings from BigQuery
|
|
1662
|
+
* Returns data in format: { instrumentId: "TICKER", ... }
|
|
1663
|
+
* @param {object} logger - Logger instance
|
|
1664
|
+
* @returns {Promise<object|null>} Ticker mappings object, or null if not found/error
|
|
1665
|
+
*/
|
|
1666
|
+
async function queryTickerMappings(logger = null) {
|
|
1667
|
+
if (process.env.BIGQUERY_ENABLED === 'false') {
|
|
1668
|
+
if (logger) logger.log('DEBUG', '[BigQuery] Ticker mappings query skipped (BIGQUERY_ENABLED=false)');
|
|
1669
|
+
return null;
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
const datasetId = process.env.BIGQUERY_DATASET_ID || 'bulltrackers_data';
|
|
1673
|
+
const tablePath = `${datasetId}.ticker_mappings`;
|
|
1674
|
+
|
|
1675
|
+
try {
|
|
1676
|
+
const sqlQuery = `
|
|
1677
|
+
SELECT
|
|
1678
|
+
instrument_id,
|
|
1679
|
+
ticker
|
|
1680
|
+
FROM \`${tablePath}\`
|
|
1681
|
+
ORDER BY instrument_id ASC
|
|
1682
|
+
`;
|
|
1683
|
+
|
|
1684
|
+
if (logger) {
|
|
1685
|
+
logger.log('INFO', `[BigQuery] 🔍 Querying ticker mappings from ${tablePath}`);
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
const rows = await query(sqlQuery, {}, logger);
|
|
1689
|
+
|
|
1690
|
+
if (!rows || rows.length === 0) {
|
|
1691
|
+
if (logger) logger.log('INFO', `[BigQuery] No ticker mappings found in ${tablePath}`);
|
|
1692
|
+
return null;
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
// Transform to expected format: { instrumentId: "TICKER" }
|
|
1696
|
+
const mappings = {};
|
|
1697
|
+
for (const row of rows) {
|
|
1698
|
+
mappings[String(row.instrument_id)] = row.ticker;
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
if (logger) {
|
|
1702
|
+
logger.log('INFO', `[BigQuery] ✅ Retrieved ${Object.keys(mappings).length} ticker mappings from ${tablePath}`);
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
return mappings;
|
|
1706
|
+
} catch (error) {
|
|
1707
|
+
if (logger) {
|
|
1708
|
+
logger.log('WARN', `[BigQuery] Ticker mappings query failed for ${tablePath}: ${error.message}`);
|
|
1709
|
+
}
|
|
1710
|
+
return null;
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1634
1714
|
module.exports = {
|
|
1635
1715
|
getBigQueryClient,
|
|
1636
1716
|
getOrCreateDataset,
|
|
@@ -1647,6 +1727,7 @@ module.exports = {
|
|
|
1647
1727
|
ensurePIMasterListTable,
|
|
1648
1728
|
ensurePIRankingsTable,
|
|
1649
1729
|
ensureInstrumentInsightsTable,
|
|
1730
|
+
ensureTickerMappingsTable,
|
|
1650
1731
|
queryPortfolioData,
|
|
1651
1732
|
queryHistoryData,
|
|
1652
1733
|
querySocialData,
|
|
@@ -1654,6 +1735,7 @@ module.exports = {
|
|
|
1654
1735
|
queryPIMasterList,
|
|
1655
1736
|
queryPIRankings,
|
|
1656
1737
|
queryInstrumentInsights,
|
|
1738
|
+
queryTickerMappings,
|
|
1657
1739
|
queryComputationResult,
|
|
1658
1740
|
queryComputationResultsRange,
|
|
1659
1741
|
checkExistingRows,
|
package/index.js
CHANGED
|
@@ -65,6 +65,8 @@ const { runPopularInvestorFetch } = require('./functions
|
|
|
65
65
|
const { backfillTaskEngineData } = require('./functions/maintenance/backfill-task-engine-data/index');
|
|
66
66
|
const { backfillPIMasterListRankings } = require('./functions/maintenance/backfill-pi-master-list-rankings/index');
|
|
67
67
|
const { backfillInstrumentInsights } = require('./functions/maintenance/backfill-instrument-insights/index');
|
|
68
|
+
const { backfillTickerMappings } = require('./functions/maintenance/backfill-ticker-mappings/index');
|
|
69
|
+
const { backfillPriceData } = require('./functions/maintenance/backfill-price-data-from-firestore/index');
|
|
68
70
|
|
|
69
71
|
// Alert System
|
|
70
72
|
const { handleAlertTrigger, handleComputationResultWrite, checkAndSendAllClearNotifications } = require('./functions/alert-system/index');
|
|
@@ -135,7 +137,9 @@ const maintenance = {
|
|
|
135
137
|
// [NEW] BigQuery backfills
|
|
136
138
|
backfillTaskEngineData,
|
|
137
139
|
backfillPIMasterListRankings,
|
|
138
|
-
backfillInstrumentInsights
|
|
140
|
+
backfillInstrumentInsights,
|
|
141
|
+
backfillTickerMappings,
|
|
142
|
+
backfillPriceData
|
|
139
143
|
};
|
|
140
144
|
|
|
141
145
|
const proxy = { handlePost };
|