feat(types): asset_class constants for ch_*, ae_*, eu_* (MiCA taxonomy)

Extends AssetClass vocabulary with 17 new constants:
- CH: ch_equity, ch_dlt_security, ch_crypto, ch_fi (FINMA)
- AE: ae_equity, ae_crypto, ae_fi, ae_tokenized_security, ae_funds (SCA/DFSA/VARA/FSRA)
- EU: eu_equity, eu_mifid_fi, eu_ucits, eu_aif, eu_art, eu_emt, eu_cas, eu_dlt_security (MiCA)

AllAssetClasses() and ValidAssetClass() updated, existing tests pass.
This commit is contained in:
2026-04-13 12:25:57 -07:00
parent 5ddcedb4da
commit cad59ba58a
2 changed files with 170 additions and 0 deletions
+114
View File
@@ -0,0 +1,114 @@
// Canonical asset class vocabulary. Every routing rule, provider config,
// jurisdiction record, and regulated entity references these constants.
// There is exactly one way to name an asset class.
package types
// AssetClass is a typed string for compile-time safety.
type AssetClass string
const (
// US asset classes
AssetClassUSEquity AssetClass = "us_equity"
AssetClassUSCrypto AssetClass = "us_crypto"
AssetClassUSOptions AssetClass = "us_options"
AssetClassUSFixedIncome AssetClass = "us_fixed_income"
// UK asset classes (FCA)
AssetClassUKEquity AssetClass = "uk_equity"
AssetClassUKCrypto AssetClass = "uk_crypto"
AssetClassUKCFDs AssetClass = "uk_cfds"
AssetClassUKFI AssetClass = "uk_fi"
// India asset classes (SEBI)
AssetClassINEquity AssetClass = "in_equity"
AssetClassINCommodity AssetClass = "in_commodity"
AssetClassINFnO AssetClass = "in_fno"
// Singapore asset classes (MAS)
AssetClassSGEquity AssetClass = "sg_equity"
AssetClassSGCrypto AssetClass = "sg_crypto"
AssetClassSGREITs AssetClass = "sg_reits"
// Australia asset classes (ASIC)
AssetClassAUEquity AssetClass = "au_equity"
AssetClassAUETF AssetClass = "au_etf"
AssetClassAUCrypto AssetClass = "au_crypto"
// Canada asset classes (CIRO)
AssetClassCAEquity AssetClass = "ca_equity"
AssetClassCAETF AssetClass = "ca_etf"
AssetClassCACrypto AssetClass = "ca_crypto"
// Brazil asset classes (CVM)
AssetClassBREquity AssetClass = "br_equity"
AssetClassBROptions AssetClass = "br_options"
AssetClassBRFIIs AssetClass = "br_fiis"
AssetClassBRCrypto AssetClass = "br_crypto"
// Switzerland asset classes (FINMA)
AssetClassCHEquity AssetClass = "ch_equity"
AssetClassCHDLTSecurity AssetClass = "ch_dlt_security"
AssetClassCHCrypto AssetClass = "ch_crypto"
AssetClassCHFI AssetClass = "ch_fi"
// UAE asset classes (SCA/DFSA/VARA/FSRA)
AssetClassAEEquity AssetClass = "ae_equity"
AssetClassAECrypto AssetClass = "ae_crypto"
AssetClassAEFI AssetClass = "ae_fi"
AssetClassAETokenizedSecurity AssetClass = "ae_tokenized_security"
AssetClassAEFunds AssetClass = "ae_funds"
// EU asset classes (MiCA-harmonized)
AssetClassEUEquity AssetClass = "eu_equity"
AssetClassEUMiFIDFI AssetClass = "eu_mifid_fi"
AssetClassEUUCITS AssetClass = "eu_ucits"
AssetClassEUAIF AssetClass = "eu_aif"
AssetClassEUART AssetClass = "eu_art"
AssetClassEUEMT AssetClass = "eu_emt"
AssetClassEUCAS AssetClass = "eu_cas"
AssetClassEUDLTSecurity AssetClass = "eu_dlt_security"
// Wildcard — matches any asset class in routing rules
AssetClassWildcard AssetClass = "*"
)
// AllAssetClasses returns every defined asset class (excluding wildcard).
func AllAssetClasses() []AssetClass {
return []AssetClass{
AssetClassUSEquity, AssetClassUSCrypto, AssetClassUSOptions, AssetClassUSFixedIncome,
AssetClassUKEquity, AssetClassUKCrypto, AssetClassUKCFDs, AssetClassUKFI,
AssetClassINEquity, AssetClassINCommodity, AssetClassINFnO,
AssetClassSGEquity, AssetClassSGCrypto, AssetClassSGREITs,
AssetClassAUEquity, AssetClassAUETF, AssetClassAUCrypto,
AssetClassCAEquity, AssetClassCAETF, AssetClassCACrypto,
AssetClassBREquity, AssetClassBROptions, AssetClassBRFIIs, AssetClassBRCrypto,
AssetClassCHEquity, AssetClassCHDLTSecurity, AssetClassCHCrypto, AssetClassCHFI,
AssetClassAEEquity, AssetClassAECrypto, AssetClassAEFI, AssetClassAETokenizedSecurity, AssetClassAEFunds,
AssetClassEUEquity, AssetClassEUMiFIDFI, AssetClassEUUCITS, AssetClassEUAIF,
AssetClassEUART, AssetClassEUEMT, AssetClassEUCAS, AssetClassEUDLTSecurity,
}
}
// ValidAssetClass returns true if s is a known asset class or wildcard.
func ValidAssetClass(s string) bool {
if s == string(AssetClassWildcard) {
return true
}
for _, ac := range AllAssetClasses() {
if string(ac) == s {
return true
}
}
return false
}
// AssetClassStrings returns all asset class string values (for Base select fields).
func AssetClassStrings() []string {
all := AllAssetClasses()
out := make([]string, len(all)+1)
for i, ac := range all {
out[i] = string(ac)
}
out[len(all)] = string(AssetClassWildcard)
return out
}
+56
View File
@@ -0,0 +1,56 @@
package types
import "testing"
func TestValidAssetClass(t *testing.T) {
valid := []string{
"us_equity", "us_crypto", "us_options", "us_fixed_income",
"uk_equity", "uk_crypto", "uk_cfds", "uk_fi",
"in_equity", "in_commodity", "in_fno",
"sg_equity", "sg_crypto", "sg_reits",
"au_equity", "au_etf", "au_crypto",
"ca_equity", "ca_etf", "ca_crypto",
"br_equity", "br_options", "br_fiis", "br_crypto",
"*",
}
for _, v := range valid {
if !ValidAssetClass(v) {
t.Errorf("ValidAssetClass(%q) = false, want true", v)
}
}
}
func TestInvalidAssetClass(t *testing.T) {
invalid := []string{"", "equity", "stock", "US_EQUITY", "us-equity", "crypto"}
for _, v := range invalid {
if ValidAssetClass(v) {
t.Errorf("ValidAssetClass(%q) = true, want false", v)
}
}
}
func TestAllAssetClassesNoDuplicates(t *testing.T) {
seen := map[AssetClass]bool{}
for _, ac := range AllAssetClasses() {
if seen[ac] {
t.Fatalf("duplicate asset class: %s", ac)
}
seen[ac] = true
}
}
func TestAssetClassStringsIncludesWildcard(t *testing.T) {
strs := AssetClassStrings()
found := false
for _, s := range strs {
if s == "*" {
found = true
}
}
if !found {
t.Fatal("AssetClassStrings() missing wildcard")
}
if len(strs) != len(AllAssetClasses())+1 {
t.Fatalf("AssetClassStrings() len = %d, want %d", len(strs), len(AllAssetClasses())+1)
}
}