| Sheet | Report Count | Reports | Key Features |
|---|---|---|---|
| 01 | 2 | RPT_000019, RPT_000059 | Dividend Receivable, PFC balance |
| 02 | 9 | RPT_000003, 030, 047, 048, 060, 061, 197, 206, 207 | Equity contract notes, IsS2 flag |
| 03 | 2 | RPT_000209, RPT_000210 | Share orders, IsS3 flag |
| 04 | 1 | RPT_000211 | Purchase/Sales summary |
| 05 | 3 | RPT_000003, 030, 025 | Transaction details, P&L (3-filter pattern) |
| 06 | 1 | RPT_000080 | Money market, PFC_Holdings |
| 07 | 1 | RPT_000049 | Interest earned, 26 measures |
| 09 | 1 | RPT_000198 | Summary transaction |
| 10 | 2 | RPT_000040, RPT_000537 | Dividend received, GenCost logic |
| 11 | 1 | RPT_000066 | Daily transaction value |
| 12 | 1 | RPT_000178 | Transaction history, 2 tables |
| 13 | 1 | (No RPT#) | Cost adjustments, 6-level nested IF |
| 14 | 1 | (No RPT#) | Domestic bonds |
Total: 14 sheets, 24 reports
| # | Filename | Size | Est. Lines | Category | Key Contents |
|---|---|---|---|---|---|
| 1 | Main.txt | 1002 B | ~40 | Config | Date formats, library connection |
| 2 | Variables.txt | 68 B | ~3 | Config | vNrUser, vSHEET05_ShowTransNo |
| 3 | Mappings.txt | 7.0 KB | ~280 | Mappings | 44 mapping tables |
| 4 | Master_Calendar.txt | 5.5 KB | ~220 | Dimension | Date dimension with fiscal periods |
| 5 | Transactions.txt | 19 KB | ~760 | Facts | Main fact + IsS2/IsS3 + Previous Day |
| 6 | Capital_Info.txt | 673 B | ~27 | Enrichment | Share capital JOIN |
| 7 | Corporate_Actions.txt | 699 B | ~28 | Enrichment | CA flags and types |
| 8 | Dividend.txt | 528 B | ~21 | Enrichment | Dividend voucher mapping |
| 9 | PFC_at_Lodgement.txt | 3.2 KB | ~128 | Enrichment | PFC balance calculation (7 steps) |
| 10 | General_Filters.txt | 1.9 KB | ~76 | Logic | 20 filter variables |
| 11 | Trans_Codes.txt | 1.5 KB | ~60 | Logic | DISABLED (##Disable syntax) |
| 12 | Grouped_Total.txt | 253 B | ~10 | Aggregation | Instrument + TOTAL rows |
| 13 | Monthly_Aggregations.txt | 160 B | ~6 | Aggregation | Month dimension (JAN-DEC + TOTAL) |
| 14 | Sheet_01.txt | 4.9 KB | ~196 | Reports | Dividend receivable, 14 measures |
| 15 | Sheet_02.txt | 4.3 KB | ~172 | Reports | Contract notes, 13 measures |
| 16 | Sheet_03.txt | 1.5 KB | ~60 | Reports | Share orders, 4 measures |
| 17 | Sheet_04.txt | 1.3 KB | ~52 | Reports | Purchase/sales summary, 6 measures |
| 18 | Sheet_05.txt | 22 KB | ~880 | Reports | Transaction details P&L, 32 measures |
| 19 | Sheet_6.txt | 708 B | ~28 | Reports | Money market, 2 measures |
| 20 | Sheet_07.txt | 5.7 KB | ~228 | Reports | Interest earned, 26 measures |
| 21 | Sheet_09.txt | 543 B | ~22 | Reports | Summary transaction, 3 measures |
| 22 | Sheet_10.txt | 5.8 KB | ~232 | Reports | Dividend received, 10 measures |
| 23 | Sheet_11.txt | 1016 B | ~41 | Reports | Daily transaction value, 5 measures |
| 24 | Sheet_12.txt | 2.8 KB | ~112 | Reports | Transaction history, 13 measures |
| 25 | Sheet_13.txt | 1.3 KB | ~52 | Reports | Cost adjustments, 1 complex measure |
| 26 | Sheet_14.txt | 392 B | ~16 | Reports | Domestic bonds, 2 measures |
| 27 | Report_Variables.txt | 697 B | ~28 | Config | 8 report title/date variables |
| 28 | Users.txt | 2.0 KB | ~80 | Admin | User management from REST API |
Totals: 28 files, ~100 KB, ~4,000 lines
┌─────────────────────────────────────────────────────────────┐
│ Phase 1: CONFIGURATION (Must run first) │
│ 1. Main.txt │
│ 2. Variables.txt │
└────────────────────────────┬────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Phase 2: REFERENCE DATA │
│ 3. Mappings.txt (44 mappings) │
│ 4. Master_Calendar.txt │
└────────────────────────────┬────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Phase 3: CORE FACTS ⚠️ CRITICAL BOTTLENECK │
│ 5. Transactions.txt (must complete before next) │
└────────────────────────────┬────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Phase 4: ENRICHMENT (All depend on Transactions) │
│ 6. Capital_Info.txt │
│ 7. Corporate_Actions.txt │
│ 8. Dividend.txt │
│ 9. PFC_at_Lodgement.txt │
└────────────────────────────┬────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Phase 5: BUSINESS LOGIC │
│ 10. General_Filters.txt (20 variables) │
│ 11. Trans_Codes.txt (DISABLED - skip) │
└────────────────────────────┬────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Phase 6: AGGREGATIONS │
│ 12. Grouped_Total.txt │
│ 13. Monthly_Aggregations.txt │
└────────────────────────────┬────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Phase 7: REPORT LAYERS (14 sheets) │
│ 14. Sheet_01.txt (Dividend Receivable) │
│ 15. Sheet_02.txt (Contract Notes) │
│ 16. Sheet_03.txt (Share Orders) │
│ 17. Sheet_04.txt (Purchase/Sales) │
│ 18. Sheet_05.txt (Transaction Details P&L) ⚠️ LARGEST │
│ 19. Sheet_6.txt (Money Market) │
│ 20. Sheet_07.txt (Interest Earned) │
│ 21. Sheet_09.txt (Summary Transaction) │
│ 22. Sheet_10.txt (Dividend Received) │
│ 23. Sheet_11.txt (Daily Transaction Value) │
│ 24. Sheet_12.txt (Transaction History) │
│ 25. Sheet_13.txt (Cost Adjustments) │
│ 26. Sheet_14.txt (Domestic Bonds) │
└────────────────────────────┬────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Phase 8: REPORT CONFIGURATION │
│ 27. Report_Variables.txt │
└─────────────────────────────────────────────────────────────┘
Optional (Independent):
│ 28. Users.txt (can run anytime)
From Transactions.txt:
From Sheet Scripts:
Current State:
[Transaction Cancellation No] = 0 AND [Transaction Status Level No] >= 30Proposed Change:
// Add at beginning of Transactions.txt
LET vQVDPath = '$(vAppPath)\QVD\Transactions_Incremental.qvd';
IF NOT IsNull(QvdCreateTime('$(vQVDPath)')) THEN
[TempLastLoad]:
LOAD MAX([Trade Date Full]) AS vMaxDate FROM [$(vQVDPath)] (qvd);
LET vLastLoadDate = Peek('vMaxDate', 0, 'TempLastLoad');
DROP TABLE TempLastLoad;
LET vIncrementalLoad = 1;
ELSE
LET vLastLoadDate = Date(AddYears(Today(), -2), 'YYYY-MM-DD');
LET vIncrementalLoad = 0;
END IF
// Modify load to add date filter
FROM [$(LIB_FOLDER)/$(DWHMODEL)/Transactions/Transactions.qvd] (qvd)
WHERE [Trade Date Full] > '$(vLastLoadDate)' // ⬅️ NEW LINE
AND [Transaction Cancellation No] = 0
AND [Transaction Status Level No] >= 30;
// After all transformations, CONCATENATE historical
IF vIncrementalLoad = 1 THEN
CONCATENATE ([Transactions])
LOAD * FROM [$(vQVDPath)] (qvd)
WHERE [Trade Date Full] <= '$(vLastLoadDate)';
END IF
// Store updated QVD at end (before DROP TABLES)
STORE [Transactions] INTO [$(vQVDPath)] (qvd);
Expected Impact:
Current State:
Proposed Change: Create reusable subroutines at the beginning of Mappings.txt:
//=================================================================
// REUSABLE SUBROUTINES FOR MAPPING CREATION
//=================================================================
SUB LoadTempMappingTable(vTempName, vQVDPath, vFields)
[$(vTempName)]:
LOAD $(vFields)
FROM [$(LIB_FOLDER)/$(DWHMODEL)/$(vQVDPath)] (qvd);
TRACE >>> Loaded $(NoOfRows('$(vTempName)')) rows into $(vTempName);
END SUB
SUB CreateMappingFromTemp(vMapName, vTempTable, vKeyField, vValueField)
[$(vMapName)]:
MAPPING LOAD [$(vKeyField)], [$(vValueField)]
RESIDENT [$(vTempTable)];
TRACE >>> Created mapping: $(vMapName);
END SUB
SUB CreateDirectMapping(vMapName, vQVDPath, vKeyField, vValueField)
[$(vMapName)]:
MAPPING LOAD [$(vKeyField)], [$(vValueField)]
FROM [$(LIB_FOLDER)/$(DWHMODEL)/$(vQVDPath)] (qvd);
TRACE >>> Created direct mapping: $(vMapName);
END SUB
//=================================================================
// Now use subroutines for all mappings
//=================================================================
// Example: Business Transaction Category (previously 12 lines, now 6)
CALL LoadTempMappingTable('TmpBCat',
'Transactions/Business Transaction Category.qvd',
'BUS_TRANS_CATEGORY_KEY, "Business Transaction Category Bus Trans Code", ...');
CALL CreateMappingFromTemp('mBusTransCode', 'TmpBCat',
'BUS_TRANS_CATEGORY_KEY', 'Business Transaction Category Bus Trans Code');
CALL CreateMappingFromTemp('mBusTransCodeName', 'TmpBCat',
'BUS_TRANS_CATEGORY_KEY', 'Business Transaction Category Bus Trans Code Name');
// ... repeat for other mappings from same table
DROP TABLE TmpBCat;
// For single mappings (previously 4 lines, now 1)
CALL CreateDirectMapping('mElementalTransCodeName',
'Transactions/Elementary Transaction.qvd',
'ELEMENTARY_TRANS_KEY', 'Elementary Transaction Elementary Trans Code Name');
Expected Impact:
Current State:
LET xSHEET05_NoOfShares = REPLACE('Sum({$(xFILTER_SHEET05A)} IF([Buy or Sell]=''Buy'', 1, -1) * [Nominal])
+ Sum({$(xFILTER_SHEET05B)} IF([Buy or Sell]=''Buy'', 1, -1) * [Nominal])
+ Sum({$(xFILTER_SHEET05C)} IF([Buy or Sell]=''Buy'', 1, -1) * [Nominal])
','@','$');
Root Cause (from Sheet_05.txt lines 23-42):
LET xFILTER_SHEET05A = '<[Bus Trans Category] = {"*Trades"}>';
LET xFILTER_SHEET05B = '<[Bus Trans Category] = {"Accounting"}, [Bus Trans SubCategory]={"Valuation", "Initialisation"}>';
LET xFILTER_SHEET05C = '<[Bus Trans Code] = {"CABuy", "CASell"}>';
Proposed Solution:
Step 1: Add IsS5 flag to Transactions.txt (after line 17, with IsS2 and IsS3):
[Transactions]:
LOAD *
, ((MATCH([Instrument Type], 'Equity','GDR/ADR',...) ...) and MATCH([Buy or Sell], 'Buy','Sell')) AS IsS2
, ((MATCH([Instrument Type], 'Equity',...) ...) OR (...)) AS IsS3
// ⬇️ NEW FLAG FOR SHEET 05
, IF(
WILDMATCH([Bus Trans Category], '*Trades')
OR ([Bus Trans Category]='Accounting' AND MATCH([Bus Trans SubCategory], 'Valuation', 'Initialisation'))
OR MATCH([Bus Trans Code], 'CABuy', 'CASell'),
1, 0
) AS IsS5
, [Security Type] & '|' & Ifrs9Purpose & '|' & [Elementary Trans Code] AS Sheet5Rpt003Level
;
Step 2: Simplify Sheet_05.txt:
// Replace 3 filter definitions (lines 23-42) with single filter:
LET xFILTER_SHEET05 = '<IsS5={1}>';
LET xFILTER_SHEET05_SELL = '<IsS5={1}, [Buy or Sell] = {"Sell"}>';
// Now all measures become single-line (4 lines → 1 line):
LET xSHEET05_NoOfShares = 'Sum({$(xFILTER_SHEET05)} IF([Buy or Sell]=''Buy'', 1, -1) * [Nominal])';
LET xSHEET05_UnitPriceMyr = 'Sum({$(xFILTER_SHEET05)} [Current Value Pc]/[Nominal])';
// ... all 32 measures simplified
Expected Impact:
Current State:
Proposed Change: Add caching logic at beginning of PFC_at_Lodgement.txt:
LET vPFCQVD = '$(vAppPath)\QVD\PFC_Latest.qvd';
LET vPFCHoldingsQVD = '$(vAppPath)\QVD\PFC_Holdings_Latest.qvd';
LET vUseCachedPFC = 0;
IF NOT IsNull(QvdCreateTime('$(vPFCQVD)')) AND NOT IsNull(QvdCreateTime('$(vPFCHoldingsQVD)')) THEN
LET vPFCAge = Now() - QvdCreateTime('$(vPFCQVD)');
IF vPFCAge < 1 THEN // Less than 1 day old
[PFC]: LOAD * FROM [$(vPFCQVD)] (qvd);
[PFC_Holdings]: LOAD * FROM [$(vPFCHoldingsQVD)] (qvd);
LET vUseCachedPFC = 1;
EXIT SCRIPT; // Skip rest of script
END IF
END IF
// Original calculation continues here if not cached...
// At end, add:
STORE [PFC] INTO [$(vPFCQVD)] (qvd);
STORE [PFC_Holdings] INTO [$(vPFCHoldingsQVD)] (qvd);
Expected Impact:
Current State:
Proposed Simplification:
// Create BalBook reference with pre-calculated per-share values
[BalBookReference]:
LOAD
HOLDING_KEY,
Num([Trade Date]) AS BB_Date,
[Transaction Ik] AS BB_TransactionIk,
[Current Value Myr] / [Nominal Basis] AS PrevValueMyr_PerShare,
[Current Value Qc] / [Nominal Basis] AS PrevValueQc_PerShare,
[Current Value Pc] / [Nominal Basis] AS PrevValuePc_PerShare,
[Balance Cost Value Pc] / [Nominal Basis] AS PrevCostPc_PerShare,
[Balance Cost Value Qc] / [Nominal Basis] AS PrevCostQc_PerShare
RESIDENT [Transactions]
WHERE MATCH([Bus Trans Code], 'BalBook');
// Create mapping for previous day (composite key: HOLDING_KEY|DATE-1)
[MapPrevValues]:
MAPPING LOAD
HOLDING_KEY & '|' & BB_Date AS PrevKey,
BB_TransactionIk & '|' &
PrevValueMyr_PerShare & '|' &
PrevValueQc_PerShare & '|' &
PrevValuePc_PerShare & '|' &
PrevCostPc_PerShare & '|' &
PrevCostQc_PerShare AS PrevValues
RESIDENT BalBookReference;
DROP TABLE BalBookReference;
// Apply to Transactions
LEFT JOIN ([Transactions])
LOAD
[Transaction Ik],
ApplyMap('MapPrevValues', HOLDING_KEY & '|' & (Num([Trade Date]) - 1), NULL()) AS PrevValuesStr
RESIDENT [Transactions]
WHERE NOT MATCH([Bus Trans Code], 'BalBook');
// Parse concatenated values
LEFT JOIN ([Transactions])
LOAD
[Transaction Ik],
Num(SubField(PrevValuesStr, '|', 1)) AS [Previous Transaction Ik],
Num(SubField(PrevValuesStr, '|', 2)) AS [Previous Value Myr],
Num(SubField(PrevValuesStr, '|', 3)) AS [Previous Value Qc],
Num(SubField(PrevValuesStr, '|', 4)) AS [Previous Value Pc],
Num(SubField(PrevValuesStr, '|', 5)) AS [Previous Cost Value Pc],
Num(SubField(PrevValuesStr, '|', 6)) AS [Previous Cost Value Qc]
RESIDENT [Transactions]
WHERE NOT IsNull(PrevValuesStr);
DROP FIELD PrevValuesStr FROM [Transactions];
Expected Impact:
| Phase | Scripts | Est. Time | Bottleneck |
|---|---|---|---|
| Configuration | 2 | 5 sec | Minimal |
| Mappings | 1 | 2 min | QVD reads (44 mappings) |
| Calendar | 1 | 30 sec | Date generation |
| Transactions Base | 1 | 25 min | Full load |
| Transactions P&L | LEFT KEEP | 3 min | Framework filter |
| Transactions Costs | LEFT KEEP | 5 min | Multiple rows per txn |
| Transactions Payments | LEFT JOIN | 1 min | Subset only |
| Previous Day | Complex | 3 min | Multiple temp tables |
| Enrichment | 4 | 4 min | PFC calculation |
| Business Logic | 1 | 10 sec | Variable creation |
| Aggregations | 2 | 20 sec | Small tables |
| Sheet Scripts | 14 | 5 min | Variable creation |
| Report Variables | 1 | 10 sec | Minimal |
| TOTAL | 28 | ~50 min | Transactions load |
| Phase | Current | After Opt #1 | After All Opts | Savings |
|---|---|---|---|---|
| Configuration | 5 sec | 5 sec | 5 sec | 0% |
| Mappings | 2 min | 2 min | 1.8 min | 10% |
| Calendar | 30 sec | 30 sec | 30 sec | 0% |
| Transactions | 25 min | 5 min | 5 min | 80% ⭐ |
| Transactions P&L | 3 min | 3 min | 3 min | 0% |
| Transactions Costs | 5 min | 5 min | 5 min | 0% |
| Transactions Payments | 1 min | 1 min | 1 min | 0% |
| Previous Day | 3 min | 3 min | 2 min | 33% ⭐ |
| Enrichment | 4 min | 4 min | 1 min | 75% ⭐ |
| Business Logic | 10 sec | 10 sec | 10 sec | 0% |
| Aggregations | 20 sec | 20 sec | 20 sec | 0% |
| Sheets | 5 min | 5 min | 4.5 min | 10% ⭐ |
| Report Variables | 10 sec | 10 sec | 10 sec | 0% |
| TOTAL | ~50 min | ~28 min | ~24 min | 52% ⭐⭐⭐ |
Daily Incremental Load: ~8-10 minutes (additional 60-70% savings)
Current Directory/
├── Main.txt
├── Variables.txt
├── Mappings.txt
├── Master_Calendar.txt
├── Transactions.txt
├── Capital_Info.txt
├── Corporate_Actions.txt
├── Dividend.txt
├── PFC_at_Lodgement.txt
├── General_Filters.txt
├── Trans_Codes.txt
├── Grouped_Total.txt
├── Monthly_Aggregations.txt
├── Sheet_01.txt
├── Sheet_02.txt
├── Sheet_03.txt
├── Sheet_04.txt
├── Sheet_05.txt
├── Sheet_6.txt
├── Sheet_07.txt
├── Sheet_09.txt
├── Sheet_10.txt
├── Sheet_11.txt
├── Sheet_12.txt
├── Sheet_13.txt
├── Sheet_14.txt
├── Report_Variables.txt
└── Users.txt
QlikSense_Portfolio_ETL/
│
├── 📁 01_Configuration/ (2 files from current)
│ ├── Main.qvs ← from Main.txt
│ └── Variables.qvs ← from Variables.txt
│
├── 📁 02_Reference_Data/
│ │
│ ├── 📁 Mappings/ (1 file, can be split later)
│ │ └── Mappings.qvs ← from Mappings.txt
│ │
│ └── 📁 Dimensions/ (1 file from current)
│ └── Master_Calendar.qvs ← from Master_Calendar.txt
│
├── 📁 03_Core_Facts/ (1 file from current)
│ └── Transactions.qvs ← from Transactions.txt
│
├── 📁 04_Enrichment/ (4 files from current)
│ ├── Capital_Info.qvs ← from Capital_Info.txt
│ ├── Corporate_Actions.qvs ← from Corporate_Actions.txt
│ ├── Dividend.qvs ← from Dividend.txt
│ └── PFC_at_Lodgement.qvs ← from PFC_at_Lodgement.txt
│
├── 📁 05_Business_Logic/ (1 file from current)
│ └── General_Filters.qvs ← from General_Filters.txt
│ (Note: Trans_Codes.txt excluded - already disabled)
│
├── 📁 06_Aggregations/ (2 files from current)
│ ├── Grouped_Total.qvs ← from Grouped_Total.txt
│ └── Monthly_Aggregations.qvs ← from Monthly_Aggregations.txt
│
├── 📁 07_Reports/
│ │
│ ├── 📁 Dividends/ (2 files from current)
│ │ ├── Sheet_01_Dividend_Receivable.qvs ← from Sheet_01.txt
│ │ └── Sheet_10_Dividend_Received.qvs ← from Sheet_10.txt
│ │
│ ├── 📁 Equity_Trading/ (4 files from current)
│ │ ├── Sheet_02_Contract_Notes.qvs ← from Sheet_02.txt
│ │ ├── Sheet_03_Share_Orders.qvs ← from Sheet_03.txt
│ │ ├── Sheet_04_Purchase_Sales_Summary.qvs ← from Sheet_04.txt
│ │ └── Sheet_05_Transaction_Details_PL.qvs ← from Sheet_05.txt
│ │
│ └── 📁 Other_Reports/ (7 files from current)
│ ├── Sheet_06_Money_Market.qvs ← from Sheet_6.txt
│ ├── Sheet_07_Interest_Earned.qvs ← from Sheet_07.txt
│ ├── Sheet_09_Summary_Transaction.qvs ← from Sheet_09.txt
│ ├── Sheet_11_Daily_Transaction_Value.qvs ← from Sheet_11.txt
│ ├── Sheet_12_Transaction_History.qvs ← from Sheet_12.txt
│ ├── Sheet_13_Cost_Adjustments.qvs ← from Sheet_13.txt
│ └── Sheet_14_Domestic_Bonds.qvs ← from Sheet_14.txt
│
├── 📁 08_Report_Configuration/ (1 file from current)
│ └── Report_Variables.qvs ← from Report_Variables.txt
│
├── 📁 09_Administration/ (1 file from current)
│ └── Users.qvs ← from Users.txt
│
├── 📁 QVD/ (NEW - for optimizations)
│ ├── Transactions_Incremental.qvd (created by Opt #1)
│ ├── PFC_Latest.qvd (created by Opt #4)
│ └── PFC_Holdings_Latest.qvd (created by Opt #4)
│
├── 📁 Documentation/ (NEW - recommended)
│ ├── README.md
│ ├── Data_Dictionary.xlsx
│ ├── Part_1_Business_Context.md
│ ├── Part_2_Dividend_Reports.md
│ ├── Part_3_Equity_Trading_Reports.md
│ ├── Part_4_Other_Reports.md
│ └── Part_5_Summary_Optimization.md
│
├── 📁 Backup/ (NEW - for safety)
│ ├── Original_Scripts_20250130/
│ │ └── (all 28 original .txt files)
│ └── Trans_Codes_Archived.txt (disabled script)
│
└── 📁 Logs/ (NEW - for monitoring)
└── Execution_Logs/
Total File Count:
| Current Filename | New Folder | New Filename | Change |
|---|---|---|---|
| Main.txt | 01_Configuration | Main.qvs | Rename only |
| Variables.txt | 01_Configuration | Variables.qvs | Rename only |
| Mappings.txt | 02_Reference_Data/Mappings | Mappings.qvs | Move + Rename |
| Master_Calendar.txt | 02_Reference_Data/Dimensions | Master_Calendar.qvs | Move + Rename |
| Transactions.txt | 03_Core_Facts | Transactions.qvs | Move + Rename |
| Capital_Info.txt | 04_Enrichment | Capital_Info.qvs | Move + Rename |
| Corporate_Actions.txt | 04_Enrichment | Corporate_Actions.qvs | Move + Rename |
| Dividend.txt | 04_Enrichment | Dividend.qvs | Move + Rename |
| PFC_at_Lodgement.txt | 04_Enrichment | PFC_at_Lodgement.qvs | Move + Rename |
| General_Filters.txt | 05_Business_Logic | General_Filters.qvs | Move + Rename |
| Trans_Codes.txt | Backup/ | Trans_Codes_Archived.txt | Archive (disabled) |
| Grouped_Total.txt | 06_Aggregations | Grouped_Total.qvs | Move + Rename |
| Monthly_Aggregations.txt | 06_Aggregations | Monthly_Aggregations.qvs | Move + Rename |
| Sheet_01.txt | 07_Reports/Dividends | Sheet_01_Dividend_Receivable.qvs | Move + Rename |
| Sheet_02.txt | 07_Reports/Equity_Trading | Sheet_02_Contract_Notes.qvs | Move + Rename |
| Sheet_03.txt | 07_Reports/Equity_Trading | Sheet_03_Share_Orders.qvs | Move + Rename |
| Sheet_04.txt | 07_Reports/Equity_Trading | Sheet_04_Purchase_Sales_Summary.qvs | Move + Rename |
| Sheet_05.txt | 07_Reports/Equity_Trading | Sheet_05_Transaction_Details_PL.qvs | Move + Rename |
| Sheet_6.txt | 07_Reports/Other_Reports | Sheet_06_Money_Market.qvs | Move + Rename (fix numbering) |
| Sheet_07.txt | 07_Reports/Other_Reports | Sheet_07_Interest_Earned.qvs | Move + Rename |
| Sheet_09.txt | 07_Reports/Other_Reports | Sheet_09_Summary_Transaction.qvs | Move + Rename |
| Sheet_10.txt | 07_Reports/Dividends | Sheet_10_Dividend_Received.qvs | Move + Rename |
| Sheet_11.txt | 07_Reports/Other_Reports | Sheet_11_Daily_Transaction_Value.qvs | Move + Rename |
| Sheet_12.txt | 07_Reports/Other_Reports | Sheet_12_Transaction_History.qvs | Move + Rename |
| Sheet_13.txt | 07_Reports/Other_Reports | Sheet_13_Cost_Adjustments.qvs | Move + Rename |
| Sheet_14.txt | 07_Reports/Other_Reports | Sheet_14_Domestic_Bonds.qvs | Move + Rename |
| Report_Variables.txt | 08_Report_Configuration | Report_Variables.qvs | Move + Rename |
| Users.txt | 09_Administration | Users.qvs | Move + Rename |
Since QlikSense requires sequential execution, create a single include file:
//=================================================================
// FILE: MASTER_LOAD_ORDER.txt (or .qvs)
// Purpose: Define execution order for all scripts
//=================================================================
// Phase 1: Configuration
$(Include=01_Configuration/Main.qvs);
$(Include=01_Configuration/Variables.qvs);
// Phase 2: Reference Data
$(Include=02_Reference_Data/Mappings/Mappings.qvs);
$(Include=02_Reference_Data/Dimensions/Master_Calendar.qvs);
// Phase 3: Core Facts
$(Include=03_Core_Facts/Transactions.qvs);
// Phase 4: Enrichment
$(Include=04_Enrichment/Capital_Info.qvs);
$(Include=04_Enrichment/Corporate_Actions.qvs);
$(Include=04_Enrichment/Dividend.qvs);
$(Include=04_Enrichment/PFC_at_Lodgement.qvs);
// Phase 5: Business Logic
$(Include=05_Business_Logic/General_Filters.qvs);
// Phase 6: Aggregations
$(Include=06_Aggregations/Grouped_Total.qvs);
$(Include=06_Aggregations/Monthly_Aggregations.qvs);
// Phase 7: Reports - Dividends
$(Include=07_Reports/Dividends/Sheet_01_Dividend_Receivable.qvs);
$(Include=07_Reports/Dividends/Sheet_10_Dividend_Received.qvs);
// Phase 7: Reports - Equity Trading
$(Include=07_Reports/Equity_Trading/Sheet_02_Contract_Notes.qvs);
$(Include=07_Reports/Equity_Trading/Sheet_03_Share_Orders.qvs);
$(Include=07_Reports/Equity_Trading/Sheet_04_Purchase_Sales_Summary.qvs);
$(Include=07_Reports/Equity_Trading/Sheet_05_Transaction_Details_PL.qvs);
// Phase 7: Reports - Other
$(Include=07_Reports/Other_Reports/Sheet_06_Money_Market.qvs);
$(Include=07_Reports/Other_Reports/Sheet_07_Interest_Earned.qvs);
$(Include=07_Reports/Other_Reports/Sheet_09_Summary_Transaction.qvs);
$(Include=07_Reports/Other_Reports/Sheet_11_Daily_Transaction_Value.qvs);
$(Include=07_Reports/Other_Reports/Sheet_12_Transaction_History.qvs);
$(Include=07_Reports/Other_Reports/Sheet_13_Cost_Adjustments.qvs);
$(Include=07_Reports/Other_Reports/Sheet_14_Domestic_Bonds.qvs);
// Phase 8: Report Configuration
$(Include=08_Report_Configuration/Report_Variables.qvs);
// Phase 9: Administration (Optional)
// $(Include=09_Administration/Users.qvs);
Format: [Category]_[Description].qvs
Examples:
Main.qvs (Configuration)Transactions.qvs (Core fact table)Sheet_01_Dividend_Receivable.qvs (Descriptive report name)| Type | Prefix | Example | Current Example |
|---|---|---|---|
| Filter Variables | flt |
fltEquity |
xFILTER_Equity |
| Measure Variables | msr |
msrSheet02_Quantity |
xSHEET02_Quantity |
| Report Variables | rpt |
rptDateTitle |
vRPT_000047_Date |
| Temp Variables | tmp |
tmpLastLoadDate |
Various |
| Config Variables | cfg |
cfgAppPath |
vAppPath |
Migration Strategy:
// Keep old for backward compatibility (Phase 1)
LET xFILTER_Equity = '<[Instrument Type] *= {"Equity",...}>';
// Add new alongside (Phase 2)
LET fltEquity = '<[Instrument Type] *= {"Equity",...}>';
// Remove old after full migration (Phase 3 - after 2-3 months)
//=================================================================
// QLIKSENSE ETL SCRIPT
//=================================================================
// Script Name: Transactions.qvs
// Original: Transactions.txt
// Module: 03_Core_Facts
// Version: 1.0.0
// Created: 2025-01-30
// Author: ETL Team
// Description: Main transaction fact table with IsS2/IsS3/IsS5 flags
//
// Dependencies:
// - 02_Reference_Data/Mappings/Mappings.qvs (44 mappings)
// - 02_Reference_Data/Dimensions/Master_Calendar.qvs
//
// Outputs:
// - [Transactions] table (~7M rows)
// - IsS2, IsS3, IsS5 flags
//
// Estimated Runtime:
// - Full load: ~25 minutes
// - Incremental: ~5 minutes (after Opt #1)
//
// Change Log:
// 2025-01-30 v1.0.0: Initial modularized version
//=================================================================
TRACE ========================================;
TRACE >>> Loading: Transactions;
TRACE >>> $(Now());
TRACE ========================================;
// Script content here...
TRACE ========================================;
TRACE >>> Completed: Transactions;
TRACE >>> Rows: $(NoOfRows('Transactions'));
TRACE ========================================;
Day 1: Full Backup
# Create dated backup folder
mkdir Backup/Original_Scripts_20250130
# Copy all current scripts
cp *.txt Backup/Original_Scripts_20250130/
# Verify backup
ls -lh Backup/Original_Scripts_20250130/
Day 2-3: Create Folder Structure
# Create all folders
mkdir -p 01_Configuration
mkdir -p 02_Reference_Data/Mappings
mkdir -p 02_Reference_Data/Dimensions
mkdir -p 03_Core_Facts
mkdir -p 04_Enrichment
mkdir -p 05_Business_Logic
mkdir -p 06_Aggregations
mkdir -p 07_Reports/Dividends
mkdir -p 07_Reports/Equity_Trading
mkdir -p 07_Reports/Other_Reports
mkdir -p 08_Report_Configuration
mkdir -p 09_Administration
mkdir -p QVD
mkdir -p Documentation
mkdir -p Logs
# Verify structure
tree -L 2
Day 4-5: Copy and Rename Files
# Configuration
cp Main.txt 01_Configuration/Main.qvs
cp Variables.txt 01_Configuration/Variables.qvs
# Reference Data
cp Mappings.txt 02_Reference_Data/Mappings/Mappings.qvs
cp Master_Calendar.txt 02_Reference_Data/Dimensions/Master_Calendar.qvs
# Core Facts
cp Transactions.txt 03_Core_Facts/Transactions.qvs
# Enrichment
cp Capital_Info.txt 04_Enrichment/Capital_Info.qvs
cp Corporate_Actions.txt 04_Enrichment/Corporate_Actions.qvs
cp Dividend.txt 04_Enrichment/Dividend.qvs
cp PFC_at_Lodgement.txt 04_Enrichment/PFC_at_Lodgement.qvs
# Business Logic
cp General_Filters.txt 05_Business_Logic/General_Filters.qvs
mv Trans_Codes.txt Backup/Trans_Codes_Archived.txt
# Aggregations
cp Grouped_Total.txt 06_Aggregations/Grouped_Total.qvs
cp Monthly_Aggregations.txt 06_Aggregations/Monthly_Aggregations.qvs
# Reports - Dividends
cp Sheet_01.txt 07_Reports/Dividends/Sheet_01_Dividend_Receivable.qvs
cp Sheet_10.txt 07_Reports/Dividends/Sheet_10_Dividend_Received.qvs
# Reports - Equity Trading
cp Sheet_02.txt 07_Reports/Equity_Trading/Sheet_02_Contract_Notes.qvs
cp Sheet_03.txt 07_Reports/Equity_Trading/Sheet_03_Share_Orders.qvs
cp Sheet_04.txt 07_Reports/Equity_Trading/Sheet_04_Purchase_Sales_Summary.qvs
cp Sheet_05.txt 07_Reports/Equity_Trading/Sheet_05_Transaction_Details_PL.qvs
# Reports - Other
cp Sheet_6.txt 07_Reports/Other_Reports/Sheet_06_Money_Market.qvs
cp Sheet_07.txt 07_Reports/Other_Reports/Sheet_07_Interest_Earned.qvs
cp Sheet_09.txt 07_Reports/Other_Reports/Sheet_09_Summary_Transaction.qvs
cp Sheet_11.txt 07_Reports/Other_Reports/Sheet_11_Daily_Transaction_Value.qvs
cp Sheet_12.txt 07_Reports/Other_Reports/Sheet_12_Transaction_History.qvs
cp Sheet_13.txt 07_Reports/Other_Reports/Sheet_13_Cost_Adjustments.qvs
cp Sheet_14.txt 07_Reports/Other_Reports/Sheet_14_Domestic_Bonds.qvs
# Report Configuration
cp Report_Variables.txt 08_Report_Configuration/Report_Variables.qvs
# Administration
cp Users.txt 09_Administration/Users.qvs
Test Modular Structure:
Validation Checklist:
Week 3: Implement Optimization #1 (Incremental Load)
Week 4: Implement Optimizations #2-5
Documentation:
Cutover:
Add to end of Transactions.qvs:
//=================================================================
// DATA QUALITY CHECKS
//=================================================================
[DQ_Checks]:
LOAD * INLINE [
CheckID, CheckName, Severity, Status, FailCount
];
// DQ-001: No NULL Transaction IK
LET vDQ001_Fail = Count(*) - Count([Transaction Ik]);
CONCATENATE ([DQ_Checks])
LOAD
'DQ-001' AS CheckID,
'No NULL Transaction IK' AS CheckName,
'HIGH' AS Severity,
IF($(vDQ001_Fail) = 0, 'PASS', 'FAIL') AS Status,
$(vDQ001_Fail) AS FailCount
AUTOGENERATE 1;
// DQ-002: Buy/Sell Classification
[TempDQ002]:
LOAD Count(*) AS vDQ002_Fail
FROM Transactions
WHERE IsNull([Buy or Sell]) AND [Bus Trans Code] <> 'BalBook';
LET vDQ002_Fail = Peek('vDQ002_Fail', 0, 'TempDQ002');
DROP TABLE TempDQ002;
CONCATENATE ([DQ_Checks])
LOAD
'DQ-002' AS CheckID,
'Buy/Sell Classification' AS CheckName,
'MEDIUM' AS Severity,
IF($(vDQ002_Fail) = 0, 'PASS', 'FAIL') AS Status,
$(vDQ002_Fail) AS FailCount
AUTOGENERATE 1;
// DQ-003: IsS2 Logic Validation
[TempDQ003]:
LOAD Count(*) AS vDQ003_Fail
FROM Transactions
WHERE IsS2 = 1 AND NOT (
(MATCH([Instrument Type], 'Equity','GDR/ADR','Right','Warrant','Covered warrant')
OR ([Instrument Type]='Fund certificate' AND MATCH([Security Type], 'ETF','ETP','ETN','REIT')))
AND MATCH([Buy or Sell], 'Buy','Sell')
);
LET vDQ003_Fail = Peek('vDQ003_Fail', 0, 'TempDQ003');
DROP TABLE TempDQ003;
CONCATENATE ([DQ_Checks])
LOAD
'DQ-003' AS CheckID,
'IsS2 Flag Logic' AS CheckName,
'HIGH' AS Severity,
IF($(vDQ003_Fail) = 0, 'PASS', 'FAIL') AS Status,
$(vDQ003_Fail) AS FailCount
AUTOGENERATE 1;
// DQ-004: Trade Date <= Settlement Date
[TempDQ004]:
LOAD Count(*) AS vDQ004_Fail
FROM Transactions
WHERE [Trade Date] > [Settlement Date];
LET vDQ004_Fail = Peek('vDQ004_Fail', 0, 'TempDQ004');
DROP TABLE TempDQ004;
CONCATENATE ([DQ_Checks])
LOAD
'DQ-004' AS CheckID,
'Trade Date <= Settlement Date' AS CheckName,
'HIGH' AS Severity,
IF($(vDQ004_Fail) = 0, 'PASS', 'FAIL') AS Status,
$(vDQ004_Fail) AS FailCount
AUTOGENERATE 1;
// DQ-005: Row Count Range
LET vTxnCount = NoOfRows('Transactions');
CONCATENATE ([DQ_Checks])
LOAD
'DQ-005' AS CheckID,
'Row Count Range (5M-10M)' AS CheckName,
'MEDIUM' AS Severity,
IF($(vTxnCount) >= 5000000 AND $(vTxnCount) <= 10000000, 'PASS', 'FAIL') AS Status,
$(vTxnCount) AS FailCount
AUTOGENERATE 1;
// Store results
STORE DQ_Checks INTO [Logs/DQ_Checks_$(Today()).qvd] (qvd);
// Count failures
LET vTotalFail = Count({<Status={'FAIL'}>} CheckID);
LET vHighFail = Count({<Status={'FAIL'}, Severity={'HIGH'}>} CheckID);
TRACE ========================================;
IF vHighFail > 0 THEN
TRACE ⚠️ WARNING: $(vHighFail) HIGH severity DQ failures!;
END IF
IF vTotalFail > 0 THEN
TRACE >>> Total DQ failures: $(vTotalFail);
ELSE
TRACE >>> All DQ checks PASSED ✓;
END IF
TRACE ========================================;
Example: 07_Reports/Dividends/README.md
# Dividend Reports
## Overview
Contains 2 scripts for dividend-related reports (4 reports total).
## Scripts
### Sheet_01_Dividend_Receivable.qvs
- **Original:** Sheet_01.txt
- **Reports:** RPT_000019, RPT_000059
- **Purpose:** Dividend receivables (unpaid dividends)
- **Key Logic:**
- PaymentClose flag
- PFC balance at lodgement (7-step)
- Filters: Payment Date >= Report Date OR PaymentClose = 0
- **Auxiliary Tables:** 4 (S1AuxNprintingSecName, S1AuxNprintingPorGroup, etc.)
- **Measures:** 14
- **Dependencies:**
- Transactions.txt (base data)
- PFC_at_Lodgement.txt (PFC balance)
- Dividend.txt (voucher mapping)
- **Runtime:** ~30 seconds
### Sheet_10_Dividend_Received.qvs
- **Original:** Sheet_10.txt
- **Reports:** RPT_000040, RPT_000537
- **Purpose:** Dividend received (paid dividends)
- **Key Logic:**
- GenCost conditional handling
- Multiple IF branches for transaction types
- Filters: PaymentClose = 1 (fully settled)
- **Auxiliary Tables:** 4 (S10AuxNprintingSecName, S10AuxNprintingPorGroup, etc.)
- **Measures:** 10
- **Dependencies:**
- Transactions.txt (base data)
- PFC_at_Lodgement.txt (PFC balance)
- **Runtime:** ~30 seconds
## Total Reports
- **2 scripts**
- **4 reports** (RPT_000019, RPT_000059, RPT_000040, RPT_000537)
- **~10.7 KB total code**
## Change Log
- 2025-01-30: Migrated from Sheet_01.txt and Sheet_10.txt
Total Duration: 8 weeks
Team Size: 2-3 developers
Risk Level: Medium (with proper backups and testing)
Objectives:
Tasks:
Deliverables:
Success Criteria:
Objectives:
Tasks:
Deliverables:
Success Criteria:
Objectives:
Tasks:
Deliverables:
Success Criteria:
Risk Mitigation:
Objectives:
Tasks:
Deliverables:
Success Criteria:
Objectives:
Tasks:
Deliverables:
Success Criteria:
Objectives:
Tasks:
Deliverables:
Success Criteria:
Objectives:
Tasks:
Deliverables:
Success Criteria:
Objectives:
Tasks:
Deliverables:
Success Criteria:
Week 1: ✓ Backup + Folder Structure
Week 2: ✓ Testing & Validation
Week 3: ⭐ Incremental Load (Opt #1)
Week 4: ⭐ Mappings + IsS5 (Opt #2 & #3)
Week 5: ⭐ PFC + Previous Day (Opt #4 & #5)
Week 6: 📊 Data Quality Framework
Week 7: 📚 Documentation
Week 8: 🚀 Final Testing & Cutover
| Metric | Baseline | Target | Measurement |
|---|---|---|---|
| Daily Reload Time | 50 min | 8-10 min | Execution log |
| Weekly Reload Time | 50 min | 24 min | Execution log |
| Code Lines | 4,000 | 3,000 | File analysis |
| Script Files | 28 flat | 28 organized | Folder count |
| Data Quality Checks | 0 | 5 automated | DQ framework |
| Documentation | Minimal | Complete | README count |
| Risk | Probability | Impact | Mitigation |
|---|---|---|---|
| Data loss | Low | High | Full backups before each change |
| Performance regression | Low | High | Benchmark after each optimization |
| Row count mismatch | Medium | High | Validate after each change |
| Report differences | Medium | Medium | Test all 24 reports weekly |
| User disruption | Low | Medium | Implement during low-usage period |