diff --git a/openbb_platform/core/openbb_core/provider/utils/country_data.json b/openbb_platform/core/openbb_core/provider/utils/country_data.json new file mode 100644 index 00000000000..3d506fd85d2 --- /dev/null +++ b/openbb_platform/core/openbb_core/provider/utils/country_data.json @@ -0,0 +1,253 @@ +{ + "countries": [ + {"alpha_2": "AF", "alpha_3": "AFG", "name": "Afghanistan", "numeric": "004"}, + {"alpha_2": "AL", "alpha_3": "ALB", "name": "Albania", "numeric": "008"}, + {"alpha_2": "DZ", "alpha_3": "DZA", "name": "Algeria", "numeric": "012"}, + {"alpha_2": "AS", "alpha_3": "ASM", "name": "American Samoa", "numeric": "016"}, + {"alpha_2": "AD", "alpha_3": "AND", "name": "Andorra", "numeric": "020"}, + {"alpha_2": "AO", "alpha_3": "AGO", "name": "Angola", "numeric": "024"}, + {"alpha_2": "AI", "alpha_3": "AIA", "name": "Anguilla", "numeric": "660"}, + {"alpha_2": "AQ", "alpha_3": "ATA", "name": "Antarctica", "numeric": "010"}, + {"alpha_2": "AG", "alpha_3": "ATG", "name": "Antigua and Barbuda", "numeric": "028"}, + {"alpha_2": "AR", "alpha_3": "ARG", "name": "Argentina", "numeric": "032"}, + {"alpha_2": "AM", "alpha_3": "ARM", "name": "Armenia", "numeric": "051"}, + {"alpha_2": "AW", "alpha_3": "ABW", "name": "Aruba", "numeric": "533"}, + {"alpha_2": "AU", "alpha_3": "AUS", "name": "Australia", "numeric": "036"}, + {"alpha_2": "AT", "alpha_3": "AUT", "name": "Austria", "numeric": "040"}, + {"alpha_2": "AZ", "alpha_3": "AZE", "name": "Azerbaijan", "numeric": "031"}, + {"alpha_2": "BS", "alpha_3": "BHS", "name": "Bahamas", "numeric": "044"}, + {"alpha_2": "BH", "alpha_3": "BHR", "name": "Bahrain", "numeric": "048"}, + {"alpha_2": "BD", "alpha_3": "BGD", "name": "Bangladesh", "numeric": "050"}, + {"alpha_2": "BB", "alpha_3": "BRB", "name": "Barbados", "numeric": "052"}, + {"alpha_2": "BY", "alpha_3": "BLR", "name": "Belarus", "numeric": "112"}, + {"alpha_2": "BE", "alpha_3": "BEL", "name": "Belgium", "numeric": "056"}, + {"alpha_2": "BZ", "alpha_3": "BLZ", "name": "Belize", "numeric": "084"}, + {"alpha_2": "BJ", "alpha_3": "BEN", "name": "Benin", "numeric": "204"}, + {"alpha_2": "BM", "alpha_3": "BMU", "name": "Bermuda", "numeric": "060"}, + {"alpha_2": "BT", "alpha_3": "BTN", "name": "Bhutan", "numeric": "064"}, + {"alpha_2": "BO", "alpha_3": "BOL", "name": "Bolivia, Plurinational State of", "numeric": "068"}, + {"alpha_2": "BQ", "alpha_3": "BES", "name": "Bonaire, Sint Eustatius and Saba", "numeric": "535"}, + {"alpha_2": "BA", "alpha_3": "BIH", "name": "Bosnia and Herzegovina", "numeric": "070"}, + {"alpha_2": "BW", "alpha_3": "BWA", "name": "Botswana", "numeric": "072"}, + {"alpha_2": "BV", "alpha_3": "BVT", "name": "Bouvet Island", "numeric": "074"}, + {"alpha_2": "BR", "alpha_3": "BRA", "name": "Brazil", "numeric": "076"}, + {"alpha_2": "IO", "alpha_3": "IOT", "name": "British Indian Ocean Territory", "numeric": "086"}, + {"alpha_2": "BN", "alpha_3": "BRN", "name": "Brunei Darussalam", "numeric": "096"}, + {"alpha_2": "BG", "alpha_3": "BGR", "name": "Bulgaria", "numeric": "100"}, + {"alpha_2": "BF", "alpha_3": "BFA", "name": "Burkina Faso", "numeric": "854"}, + {"alpha_2": "BI", "alpha_3": "BDI", "name": "Burundi", "numeric": "108"}, + {"alpha_2": "CV", "alpha_3": "CPV", "name": "Cabo Verde", "numeric": "132"}, + {"alpha_2": "KH", "alpha_3": "KHM", "name": "Cambodia", "numeric": "116"}, + {"alpha_2": "CM", "alpha_3": "CMR", "name": "Cameroon", "numeric": "120"}, + {"alpha_2": "CA", "alpha_3": "CAN", "name": "Canada", "numeric": "124"}, + {"alpha_2": "KY", "alpha_3": "CYM", "name": "Cayman Islands", "numeric": "136"}, + {"alpha_2": "CF", "alpha_3": "CAF", "name": "Central African Republic", "numeric": "140"}, + {"alpha_2": "TD", "alpha_3": "TCD", "name": "Chad", "numeric": "148"}, + {"alpha_2": "CL", "alpha_3": "CHL", "name": "Chile", "numeric": "152"}, + {"alpha_2": "CN", "alpha_3": "CHN", "name": "China", "numeric": "156"}, + {"alpha_2": "CX", "alpha_3": "CXR", "name": "Christmas Island", "numeric": "162"}, + {"alpha_2": "CC", "alpha_3": "CCK", "name": "Cocos (Keeling) Islands", "numeric": "166"}, + {"alpha_2": "CO", "alpha_3": "COL", "name": "Colombia", "numeric": "170"}, + {"alpha_2": "KM", "alpha_3": "COM", "name": "Comoros", "numeric": "174"}, + {"alpha_2": "CG", "alpha_3": "COG", "name": "Congo", "numeric": "178"}, + {"alpha_2": "CD", "alpha_3": "COD", "name": "Congo, Democratic Republic of the", "numeric": "180"}, + {"alpha_2": "CK", "alpha_3": "COK", "name": "Cook Islands", "numeric": "184"}, + {"alpha_2": "CR", "alpha_3": "CRI", "name": "Costa Rica", "numeric": "188"}, + {"alpha_2": "HR", "alpha_3": "HRV", "name": "Croatia", "numeric": "191"}, + {"alpha_2": "CU", "alpha_3": "CUB", "name": "Cuba", "numeric": "192"}, + {"alpha_2": "CW", "alpha_3": "CUW", "name": "Curaçao", "numeric": "531"}, + {"alpha_2": "CY", "alpha_3": "CYP", "name": "Cyprus", "numeric": "196"}, + {"alpha_2": "CZ", "alpha_3": "CZE", "name": "Czechia", "numeric": "203"}, + {"alpha_2": "CI", "alpha_3": "CIV", "name": "Côte d'Ivoire", "numeric": "384"}, + {"alpha_2": "DK", "alpha_3": "DNK", "name": "Denmark", "numeric": "208"}, + {"alpha_2": "DJ", "alpha_3": "DJI", "name": "Djibouti", "numeric": "262"}, + {"alpha_2": "DM", "alpha_3": "DMA", "name": "Dominica", "numeric": "212"}, + {"alpha_2": "DO", "alpha_3": "DOM", "name": "Dominican Republic", "numeric": "214"}, + {"alpha_2": "EC", "alpha_3": "ECU", "name": "Ecuador", "numeric": "218"}, + {"alpha_2": "EG", "alpha_3": "EGY", "name": "Egypt", "numeric": "818"}, + {"alpha_2": "SV", "alpha_3": "SLV", "name": "El Salvador", "numeric": "222"}, + {"alpha_2": "GQ", "alpha_3": "GNQ", "name": "Equatorial Guinea", "numeric": "226"}, + {"alpha_2": "ER", "alpha_3": "ERI", "name": "Eritrea", "numeric": "232"}, + {"alpha_2": "EE", "alpha_3": "EST", "name": "Estonia", "numeric": "233"}, + {"alpha_2": "SZ", "alpha_3": "SWZ", "name": "Eswatini", "numeric": "748"}, + {"alpha_2": "ET", "alpha_3": "ETH", "name": "Ethiopia", "numeric": "231"}, + {"alpha_2": "FK", "alpha_3": "FLK", "name": "Falkland Islands (Malvinas)", "numeric": "238"}, + {"alpha_2": "FO", "alpha_3": "FRO", "name": "Faroe Islands", "numeric": "234"}, + {"alpha_2": "FJ", "alpha_3": "FJI", "name": "Fiji", "numeric": "242"}, + {"alpha_2": "FI", "alpha_3": "FIN", "name": "Finland", "numeric": "246"}, + {"alpha_2": "FR", "alpha_3": "FRA", "name": "France", "numeric": "250"}, + {"alpha_2": "GF", "alpha_3": "GUF", "name": "French Guiana", "numeric": "254"}, + {"alpha_2": "PF", "alpha_3": "PYF", "name": "French Polynesia", "numeric": "258"}, + {"alpha_2": "TF", "alpha_3": "ATF", "name": "French Southern Territories", "numeric": "260"}, + {"alpha_2": "GA", "alpha_3": "GAB", "name": "Gabon", "numeric": "266"}, + {"alpha_2": "GM", "alpha_3": "GMB", "name": "Gambia", "numeric": "270"}, + {"alpha_2": "GE", "alpha_3": "GEO", "name": "Georgia", "numeric": "268"}, + {"alpha_2": "DE", "alpha_3": "DEU", "name": "Germany", "numeric": "276"}, + {"alpha_2": "GH", "alpha_3": "GHA", "name": "Ghana", "numeric": "288"}, + {"alpha_2": "GI", "alpha_3": "GIB", "name": "Gibraltar", "numeric": "292"}, + {"alpha_2": "GR", "alpha_3": "GRC", "name": "Greece", "numeric": "300"}, + {"alpha_2": "GL", "alpha_3": "GRL", "name": "Greenland", "numeric": "304"}, + {"alpha_2": "GD", "alpha_3": "GRD", "name": "Grenada", "numeric": "308"}, + {"alpha_2": "GP", "alpha_3": "GLP", "name": "Guadeloupe", "numeric": "312"}, + {"alpha_2": "GU", "alpha_3": "GUM", "name": "Guam", "numeric": "316"}, + {"alpha_2": "GT", "alpha_3": "GTM", "name": "Guatemala", "numeric": "320"}, + {"alpha_2": "GG", "alpha_3": "GGY", "name": "Guernsey", "numeric": "831"}, + {"alpha_2": "GN", "alpha_3": "GIN", "name": "Guinea", "numeric": "324"}, + {"alpha_2": "GW", "alpha_3": "GNB", "name": "Guinea-Bissau", "numeric": "624"}, + {"alpha_2": "GY", "alpha_3": "GUY", "name": "Guyana", "numeric": "328"}, + {"alpha_2": "HT", "alpha_3": "HTI", "name": "Haiti", "numeric": "332"}, + {"alpha_2": "HM", "alpha_3": "HMD", "name": "Heard Island and McDonald Islands", "numeric": "334"}, + {"alpha_2": "VA", "alpha_3": "VAT", "name": "Holy See", "numeric": "336"}, + {"alpha_2": "HN", "alpha_3": "HND", "name": "Honduras", "numeric": "340"}, + {"alpha_2": "HK", "alpha_3": "HKG", "name": "Hong Kong", "numeric": "344"}, + {"alpha_2": "HU", "alpha_3": "HUN", "name": "Hungary", "numeric": "348"}, + {"alpha_2": "IS", "alpha_3": "ISL", "name": "Iceland", "numeric": "352"}, + {"alpha_2": "IN", "alpha_3": "IND", "name": "India", "numeric": "356"}, + {"alpha_2": "ID", "alpha_3": "IDN", "name": "Indonesia", "numeric": "360"}, + {"alpha_2": "IR", "alpha_3": "IRN", "name": "Iran, Islamic Republic of", "numeric": "364"}, + {"alpha_2": "IQ", "alpha_3": "IRQ", "name": "Iraq", "numeric": "368"}, + {"alpha_2": "IE", "alpha_3": "IRL", "name": "Ireland", "numeric": "372"}, + {"alpha_2": "IM", "alpha_3": "IMN", "name": "Isle of Man", "numeric": "833"}, + {"alpha_2": "IL", "alpha_3": "ISR", "name": "Israel", "numeric": "376"}, + {"alpha_2": "IT", "alpha_3": "ITA", "name": "Italy", "numeric": "380"}, + {"alpha_2": "JM", "alpha_3": "JAM", "name": "Jamaica", "numeric": "388"}, + {"alpha_2": "JP", "alpha_3": "JPN", "name": "Japan", "numeric": "392"}, + {"alpha_2": "JE", "alpha_3": "JEY", "name": "Jersey", "numeric": "832"}, + {"alpha_2": "JO", "alpha_3": "JOR", "name": "Jordan", "numeric": "400"}, + {"alpha_2": "KZ", "alpha_3": "KAZ", "name": "Kazakhstan", "numeric": "398"}, + {"alpha_2": "KE", "alpha_3": "KEN", "name": "Kenya", "numeric": "404"}, + {"alpha_2": "KI", "alpha_3": "KIR", "name": "Kiribati", "numeric": "296"}, + {"alpha_2": "KP", "alpha_3": "PRK", "name": "Korea, Democratic People's Republic of", "numeric": "408"}, + {"alpha_2": "KR", "alpha_3": "KOR", "name": "Korea, Republic of", "numeric": "410"}, + {"alpha_2": "KW", "alpha_3": "KWT", "name": "Kuwait", "numeric": "414"}, + {"alpha_2": "KG", "alpha_3": "KGZ", "name": "Kyrgyzstan", "numeric": "417"}, + {"alpha_2": "LA", "alpha_3": "LAO", "name": "Lao People's Democratic Republic", "numeric": "418"}, + {"alpha_2": "LV", "alpha_3": "LVA", "name": "Latvia", "numeric": "428"}, + {"alpha_2": "LB", "alpha_3": "LBN", "name": "Lebanon", "numeric": "422"}, + {"alpha_2": "LS", "alpha_3": "LSO", "name": "Lesotho", "numeric": "426"}, + {"alpha_2": "LR", "alpha_3": "LBR", "name": "Liberia", "numeric": "430"}, + {"alpha_2": "LY", "alpha_3": "LBY", "name": "Libya", "numeric": "434"}, + {"alpha_2": "LI", "alpha_3": "LIE", "name": "Liechtenstein", "numeric": "438"}, + {"alpha_2": "LT", "alpha_3": "LTU", "name": "Lithuania", "numeric": "440"}, + {"alpha_2": "LU", "alpha_3": "LUX", "name": "Luxembourg", "numeric": "442"}, + {"alpha_2": "MO", "alpha_3": "MAC", "name": "Macao", "numeric": "446"}, + {"alpha_2": "MG", "alpha_3": "MDG", "name": "Madagascar", "numeric": "450"}, + {"alpha_2": "MW", "alpha_3": "MWI", "name": "Malawi", "numeric": "454"}, + {"alpha_2": "MY", "alpha_3": "MYS", "name": "Malaysia", "numeric": "458"}, + {"alpha_2": "MV", "alpha_3": "MDV", "name": "Maldives", "numeric": "462"}, + {"alpha_2": "ML", "alpha_3": "MLI", "name": "Mali", "numeric": "466"}, + {"alpha_2": "MT", "alpha_3": "MLT", "name": "Malta", "numeric": "470"}, + {"alpha_2": "MH", "alpha_3": "MHL", "name": "Marshall Islands", "numeric": "584"}, + {"alpha_2": "MQ", "alpha_3": "MTQ", "name": "Martinique", "numeric": "474"}, + {"alpha_2": "MR", "alpha_3": "MRT", "name": "Mauritania", "numeric": "478"}, + {"alpha_2": "MU", "alpha_3": "MUS", "name": "Mauritius", "numeric": "480"}, + {"alpha_2": "YT", "alpha_3": "MYT", "name": "Mayotte", "numeric": "175"}, + {"alpha_2": "MX", "alpha_3": "MEX", "name": "Mexico", "numeric": "484"}, + {"alpha_2": "FM", "alpha_3": "FSM", "name": "Micronesia, Federated States of", "numeric": "583"}, + {"alpha_2": "MD", "alpha_3": "MDA", "name": "Moldova, Republic of", "numeric": "498"}, + {"alpha_2": "MC", "alpha_3": "MCO", "name": "Monaco", "numeric": "492"}, + {"alpha_2": "MN", "alpha_3": "MNG", "name": "Mongolia", "numeric": "496"}, + {"alpha_2": "ME", "alpha_3": "MNE", "name": "Montenegro", "numeric": "499"}, + {"alpha_2": "MS", "alpha_3": "MSR", "name": "Montserrat", "numeric": "500"}, + {"alpha_2": "MA", "alpha_3": "MAR", "name": "Morocco", "numeric": "504"}, + {"alpha_2": "MZ", "alpha_3": "MOZ", "name": "Mozambique", "numeric": "508"}, + {"alpha_2": "MM", "alpha_3": "MMR", "name": "Myanmar", "numeric": "104"}, + {"alpha_2": "NA", "alpha_3": "NAM", "name": "Namibia", "numeric": "516"}, + {"alpha_2": "NR", "alpha_3": "NRU", "name": "Nauru", "numeric": "520"}, + {"alpha_2": "NP", "alpha_3": "NPL", "name": "Nepal", "numeric": "524"}, + {"alpha_2": "NL", "alpha_3": "NLD", "name": "Netherlands", "numeric": "528"}, + {"alpha_2": "NC", "alpha_3": "NCL", "name": "New Caledonia", "numeric": "540"}, + {"alpha_2": "NZ", "alpha_3": "NZL", "name": "New Zealand", "numeric": "554"}, + {"alpha_2": "NI", "alpha_3": "NIC", "name": "Nicaragua", "numeric": "558"}, + {"alpha_2": "NE", "alpha_3": "NER", "name": "Niger", "numeric": "562"}, + {"alpha_2": "NG", "alpha_3": "NGA", "name": "Nigeria", "numeric": "566"}, + {"alpha_2": "NU", "alpha_3": "NIU", "name": "Niue", "numeric": "570"}, + {"alpha_2": "NF", "alpha_3": "NFK", "name": "Norfolk Island", "numeric": "574"}, + {"alpha_2": "MK", "alpha_3": "MKD", "name": "North Macedonia", "numeric": "807"}, + {"alpha_2": "MP", "alpha_3": "MNP", "name": "Northern Mariana Islands", "numeric": "580"}, + {"alpha_2": "NO", "alpha_3": "NOR", "name": "Norway", "numeric": "578"}, + {"alpha_2": "OM", "alpha_3": "OMN", "name": "Oman", "numeric": "512"}, + {"alpha_2": "PK", "alpha_3": "PAK", "name": "Pakistan", "numeric": "586"}, + {"alpha_2": "PW", "alpha_3": "PLW", "name": "Palau", "numeric": "585"}, + {"alpha_2": "PS", "alpha_3": "PSE", "name": "Palestine, State of", "numeric": "275"}, + {"alpha_2": "PA", "alpha_3": "PAN", "name": "Panama", "numeric": "591"}, + {"alpha_2": "PG", "alpha_3": "PNG", "name": "Papua New Guinea", "numeric": "598"}, + {"alpha_2": "PY", "alpha_3": "PRY", "name": "Paraguay", "numeric": "600"}, + {"alpha_2": "PE", "alpha_3": "PER", "name": "Peru", "numeric": "604"}, + {"alpha_2": "PH", "alpha_3": "PHL", "name": "Philippines", "numeric": "608"}, + {"alpha_2": "PN", "alpha_3": "PCN", "name": "Pitcairn", "numeric": "612"}, + {"alpha_2": "PL", "alpha_3": "POL", "name": "Poland", "numeric": "616"}, + {"alpha_2": "PT", "alpha_3": "PRT", "name": "Portugal", "numeric": "620"}, + {"alpha_2": "PR", "alpha_3": "PRI", "name": "Puerto Rico", "numeric": "630"}, + {"alpha_2": "QA", "alpha_3": "QAT", "name": "Qatar", "numeric": "634"}, + {"alpha_2": "RO", "alpha_3": "ROU", "name": "Romania", "numeric": "642"}, + {"alpha_2": "RU", "alpha_3": "RUS", "name": "Russian Federation", "numeric": "643"}, + {"alpha_2": "RW", "alpha_3": "RWA", "name": "Rwanda", "numeric": "646"}, + {"alpha_2": "RE", "alpha_3": "REU", "name": "Réunion", "numeric": "638"}, + {"alpha_2": "BL", "alpha_3": "BLM", "name": "Saint Barthélemy", "numeric": "652"}, + {"alpha_2": "SH", "alpha_3": "SHN", "name": "Saint Helena, Ascension and Tristan da Cunha", "numeric": "654"}, + {"alpha_2": "KN", "alpha_3": "KNA", "name": "Saint Kitts and Nevis", "numeric": "659"}, + {"alpha_2": "LC", "alpha_3": "LCA", "name": "Saint Lucia", "numeric": "662"}, + {"alpha_2": "MF", "alpha_3": "MAF", "name": "Saint Martin (French part)", "numeric": "663"}, + {"alpha_2": "PM", "alpha_3": "SPM", "name": "Saint Pierre and Miquelon", "numeric": "666"}, + {"alpha_2": "VC", "alpha_3": "VCT", "name": "Saint Vincent and the Grenadines", "numeric": "670"}, + {"alpha_2": "WS", "alpha_3": "WSM", "name": "Samoa", "numeric": "882"}, + {"alpha_2": "SM", "alpha_3": "SMR", "name": "San Marino", "numeric": "674"}, + {"alpha_2": "ST", "alpha_3": "STP", "name": "Sao Tome and Principe", "numeric": "678"}, + {"alpha_2": "SA", "alpha_3": "SAU", "name": "Saudi Arabia", "numeric": "682"}, + {"alpha_2": "SN", "alpha_3": "SEN", "name": "Senegal", "numeric": "686"}, + {"alpha_2": "RS", "alpha_3": "SRB", "name": "Serbia", "numeric": "688"}, + {"alpha_2": "SC", "alpha_3": "SYC", "name": "Seychelles", "numeric": "690"}, + {"alpha_2": "SL", "alpha_3": "SLE", "name": "Sierra Leone", "numeric": "694"}, + {"alpha_2": "SG", "alpha_3": "SGP", "name": "Singapore", "numeric": "702"}, + {"alpha_2": "SX", "alpha_3": "SXM", "name": "Sint Maarten (Dutch part)", "numeric": "534"}, + {"alpha_2": "SK", "alpha_3": "SVK", "name": "Slovakia", "numeric": "703"}, + {"alpha_2": "SI", "alpha_3": "SVN", "name": "Slovenia", "numeric": "705"}, + {"alpha_2": "SB", "alpha_3": "SLB", "name": "Solomon Islands", "numeric": "090"}, + {"alpha_2": "SO", "alpha_3": "SOM", "name": "Somalia", "numeric": "706"}, + {"alpha_2": "ZA", "alpha_3": "ZAF", "name": "South Africa", "numeric": "710"}, + {"alpha_2": "GS", "alpha_3": "SGS", "name": "South Georgia and the South Sandwich Islands", "numeric": "239"}, + {"alpha_2": "SS", "alpha_3": "SSD", "name": "South Sudan", "numeric": "728"}, + {"alpha_2": "ES", "alpha_3": "ESP", "name": "Spain", "numeric": "724"}, + {"alpha_2": "LK", "alpha_3": "LKA", "name": "Sri Lanka", "numeric": "144"}, + {"alpha_2": "SD", "alpha_3": "SDN", "name": "Sudan", "numeric": "729"}, + {"alpha_2": "SR", "alpha_3": "SUR", "name": "Suriname", "numeric": "740"}, + {"alpha_2": "SJ", "alpha_3": "SJM", "name": "Svalbard and Jan Mayen", "numeric": "744"}, + {"alpha_2": "SE", "alpha_3": "SWE", "name": "Sweden", "numeric": "752"}, + {"alpha_2": "CH", "alpha_3": "CHE", "name": "Switzerland", "numeric": "756"}, + {"alpha_2": "SY", "alpha_3": "SYR", "name": "Syrian Arab Republic", "numeric": "760"}, + {"alpha_2": "TW", "alpha_3": "TWN", "name": "Taiwan, Province of China", "numeric": "158"}, + {"alpha_2": "TJ", "alpha_3": "TJK", "name": "Tajikistan", "numeric": "762"}, + {"alpha_2": "TZ", "alpha_3": "TZA", "name": "Tanzania, United Republic of", "numeric": "834"}, + {"alpha_2": "TH", "alpha_3": "THA", "name": "Thailand", "numeric": "764"}, + {"alpha_2": "TL", "alpha_3": "TLS", "name": "Timor-Leste", "numeric": "626"}, + {"alpha_2": "TG", "alpha_3": "TGO", "name": "Togo", "numeric": "768"}, + {"alpha_2": "TK", "alpha_3": "TKL", "name": "Tokelau", "numeric": "772"}, + {"alpha_2": "TO", "alpha_3": "TON", "name": "Tonga", "numeric": "776"}, + {"alpha_2": "TT", "alpha_3": "TTO", "name": "Trinidad and Tobago", "numeric": "780"}, + {"alpha_2": "TN", "alpha_3": "TUN", "name": "Tunisia", "numeric": "788"}, + {"alpha_2": "TR", "alpha_3": "TUR", "name": "Turkey", "numeric": "792"}, + {"alpha_2": "TM", "alpha_3": "TKM", "name": "Turkmenistan", "numeric": "795"}, + {"alpha_2": "TC", "alpha_3": "TCA", "name": "Turks and Caicos Islands", "numeric": "796"}, + {"alpha_2": "TV", "alpha_3": "TUV", "name": "Tuvalu", "numeric": "798"}, + {"alpha_2": "UG", "alpha_3": "UGA", "name": "Uganda", "numeric": "800"}, + {"alpha_2": "UA", "alpha_3": "UKR", "name": "Ukraine", "numeric": "804"}, + {"alpha_2": "AE", "alpha_3": "ARE", "name": "United Arab Emirates", "numeric": "784"}, + {"alpha_2": "GB", "alpha_3": "GBR", "name": "United Kingdom", "numeric": "826"}, + {"alpha_2": "US", "alpha_3": "USA", "name": "United States", "numeric": "840"}, + {"alpha_2": "UM", "alpha_3": "UMI", "name": "United States Minor Outlying Islands", "numeric": "581"}, + {"alpha_2": "UY", "alpha_3": "URY", "name": "Uruguay", "numeric": "858"}, + {"alpha_2": "UZ", "alpha_3": "UZB", "name": "Uzbekistan", "numeric": "860"}, + {"alpha_2": "VU", "alpha_3": "VUT", "name": "Vanuatu", "numeric": "548"}, + {"alpha_2": "VE", "alpha_3": "VEN", "name": "Venezuela, Bolivarian Republic of", "numeric": "862"}, + {"alpha_2": "VN", "alpha_3": "VNM", "name": "Viet Nam", "numeric": "704"}, + {"alpha_2": "VG", "alpha_3": "VGB", "name": "Virgin Islands, British", "numeric": "092"}, + {"alpha_2": "VI", "alpha_3": "VIR", "name": "Virgin Islands, U.S.", "numeric": "850"}, + {"alpha_2": "WF", "alpha_3": "WLF", "name": "Wallis and Futuna", "numeric": "876"}, + {"alpha_2": "EH", "alpha_3": "ESH", "name": "Western Sahara", "numeric": "732"}, + {"alpha_2": "YE", "alpha_3": "YEM", "name": "Yemen", "numeric": "887"}, + {"alpha_2": "ZM", "alpha_3": "ZMB", "name": "Zambia", "numeric": "894"}, + {"alpha_2": "ZW", "alpha_3": "ZWE", "name": "Zimbabwe", "numeric": "716"}, + {"alpha_2": "AX", "alpha_3": "ALA", "name": "Åland Islands", "numeric": "248"} + ] +} diff --git a/openbb_platform/core/openbb_core/provider/utils/country_utils.py b/openbb_platform/core/openbb_core/provider/utils/country_utils.py new file mode 100644 index 00000000000..aeed69bcb1a --- /dev/null +++ b/openbb_platform/core/openbb_core/provider/utils/country_utils.py @@ -0,0 +1,182 @@ +"""Utilities for standardizing country inputs across providers using ISO 3166 standards. + +This module provides a Country type that inherits from str for type checker compatibility +while providing full access to ISO 3166 country data via a static dataset. + +Providers can access alpha_2, alpha_3, name, and numeric properties as needed. + +References: + - ISO 3166-1: https://en.wikipedia.org/wiki/ISO_3166-1 +""" + +import json +from pathlib import Path +from typing import Any + +from pydantic_core import core_schema + + +def _load_country_data() -> dict[str, dict[str, str]]: + """Load country data from JSON and build lookup indices. + + Returns a dict with lookup keys (alpha_2, alpha_3, name variants) mapping to country data. + """ + data_path = Path(__file__).parent / "country_data.json" + with open(data_path, encoding="utf-8") as f: + data = json.load(f) + + lookup: dict[str, dict[str, str]] = {} + for country in data["countries"]: + # Index by alpha_2 (case-insensitive) + lookup[country["alpha_2"].upper()] = country + lookup[country["alpha_2"].lower()] = country + + # Index by alpha_3 (case-insensitive) + lookup[country["alpha_3"].upper()] = country + lookup[country["alpha_3"].lower()] = country + + # Index by name (case-insensitive) + name_lower = country["name"].lower() + lookup[name_lower] = country + lookup[country["name"]] = country + + # Index by snake_case name + snake_name = name_lower.replace(" ", "_").replace(",", "").replace("'", "") + lookup[snake_name] = country + + return lookup + + +# Load once at module import - no decompression needed, just simple JSON parse +_COUNTRY_LOOKUP = _load_country_data() + + +class Country(str): + """Country string type with full ISO 3166 data access. + + Inherits from str (storing alpha_2 code) for type checker compatibility + while providing access to alpha_2, alpha_3, name, and numeric properties. + + Accepts: + - ISO 3166-1 alpha-2 codes (e.g., "US", "us") + - ISO 3166-1 alpha-3 codes (e.g., "USA", "usa") + - Full country names (e.g., "United States") + - lower_snake_case names (e.g., "united_states") + + Examples + -------- + >>> c = Country("united_states") + >>> str(c) + 'US' + >>> c.alpha_2 + 'US' + >>> c.alpha_3 + 'USA' + >>> c.name + 'United States' + """ + + _country_data: dict[str, str] + + def __new__(cls, value: Any) -> "Country": + """Create a new Country instance. + + Parameters + ---------- + value : Any + Country input (alpha-2, alpha-3, name, or lower_snake_case). + + Returns + ------- + Country + A Country instance storing the alpha_2 code as its string value. + + Raises + ------ + ValueError + If the country cannot be resolved. + """ + country_data = ( + value._country_data + if isinstance(value, Country) + else cls._lookup_country(value) + ) + + # Create str instance with the alpha_2 code + instance = super().__new__(cls, country_data["alpha_2"]) + # Store the country data dict + instance._country_data = country_data + return instance + + @staticmethod + def _lookup_country(value: Any) -> dict[str, str]: + """Look up a country from various input formats. + + Parameters + ---------- + value : Any + Country input to look up. + + Returns + ------- + dict[str, str] + The country data dictionary with alpha_2, alpha_3, name, numeric. + + Raises + ------ + ValueError + If the country cannot be found. + """ + val = str(value).strip() + + # Convert lower_snake_case to lookup key + if "_" in val: + val = val.replace("_", " ") + + # Try direct lookup + lookup_key = val.lower() + if lookup_key in _COUNTRY_LOOKUP: + return _COUNTRY_LOOKUP[lookup_key] + + # Try original case + if val in _COUNTRY_LOOKUP: + return _COUNTRY_LOOKUP[val] + + raise ValueError( + f"Invalid country: '{value}'. " + "Accepts ISO 3166-1 alpha-2 codes (e.g., 'US'), " + "alpha-3 codes (e.g., 'USA'), " + "or country names (e.g., 'United States', 'united_states')." + ) + + @property + def alpha_2(self) -> str: + """ISO 3166-1 alpha-2 code (e.g., 'US').""" + return self._country_data["alpha_2"] + + @property + def alpha_3(self) -> str: + """ISO 3166-1 alpha-3 code (e.g., 'USA').""" + return self._country_data["alpha_3"] + + @property + def name(self) -> str: + """The country's official designation (e.g., 'United States').""" + return self._country_data["name"] + + @property + def numeric(self) -> str | None: + """ISO 3166-1 numeric code (e.g., '840'), if available.""" + return self._country_data.get("numeric") + + @classmethod + def __get_pydantic_core_schema__(cls, _source_type: Any, _handler: Any) -> Any: + """Return the Pydantic core schema for validation.""" + return core_schema.no_info_after_validator_function( + cls, + core_schema.str_schema(), + ) + + +# Backwards-compatible alias +CountryParam = Country diff --git a/openbb_platform/core/tests/provider/utils/test_country_utils.py b/openbb_platform/core/tests/provider/utils/test_country_utils.py new file mode 100644 index 00000000000..20182fd637c --- /dev/null +++ b/openbb_platform/core/tests/provider/utils/test_country_utils.py @@ -0,0 +1,99 @@ +"""Tests for country_utils module.""" + +import pytest +from openbb_core.provider.utils.country_utils import Country, CountryParam +from pydantic import BaseModel, ValidationError + + +class CountryTestModel(BaseModel): + """Test model for Country validation.""" + + country: Country | None = None + + +class TestCountry: + """Tests for Country type.""" + + def test_iso_alpha2_code(self): + """ISO alpha-2 codes should be accepted.""" + model = CountryTestModel(country="US") + assert str(model.country) == "US" + assert model.country.alpha_2 == "US" + assert model.country.alpha_3 == "USA" + + model = CountryTestModel(country="us") + assert str(model.country) == "US" + + model = CountryTestModel(country="DE") + assert str(model.country) == "DE" + assert model.country.alpha_3 == "DEU" + + def test_iso_alpha3_code(self): + """ISO alpha-3 codes should be accepted.""" + model = CountryTestModel(country="USA") + assert str(model.country) == "US" + assert model.country.alpha_2 == "US" + assert model.country.alpha_3 == "USA" + + model = CountryTestModel(country="deu") + assert str(model.country) == "DE" + + def test_country_name(self): + """Full country names should resolve to alpha-2 codes.""" + model = CountryTestModel(country="United States") + assert str(model.country) == "US" + assert model.country.name == "United States" + + model = CountryTestModel(country="Germany") + assert str(model.country) == "DE" + assert model.country.name == "Germany" + + model = CountryTestModel(country="United Kingdom") + assert str(model.country) == "GB" + + def test_lower_snake_case(self): + """lower_snake_case names should be accepted.""" + model = CountryTestModel(country="united_states") + assert str(model.country) == "US" + + model = CountryTestModel(country="united_kingdom") + assert str(model.country) == "GB" + + def test_none_value(self): + """None values should pass through.""" + model = CountryTestModel(country=None) + assert model.country is None + + def test_invalid_country(self): + """Invalid country names should raise ValidationError.""" + with pytest.raises(ValidationError): + CountryTestModel(country="InvalidCountry") + + with pytest.raises(ValidationError): + CountryTestModel(country="XX") # Invalid ISO code + + def test_country_properties(self): + """Country should expose all ISO properties.""" + c = Country("US") + assert c.alpha_2 == "US" + assert c.alpha_3 == "USA" + assert c.name == "United States" + assert c.numeric == "840" + + def test_str_inheritance(self): + """Country should behave like a string.""" + c = Country("US") + assert isinstance(c, str) + assert c == "US" + assert c.lower() == "us" + assert f"Country: {c}" == "Country: US" + + def test_model_dump(self): + """model_dump should serialize to string.""" + model = CountryTestModel(country="united_states") + dumped = model.model_dump() + assert dumped["country"] == "US" + + def test_country_param_alias(self): + """CountryParam should be an alias for Country.""" + assert CountryParam is Country diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/equity_screener.py b/openbb_platform/providers/fmp/openbb_fmp/models/equity_screener.py index ba4509179c0..f04558ac4ae 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/equity_screener.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/equity_screener.py @@ -9,6 +9,7 @@ from openbb_core.provider.standard_models.equity_screener import ( EquityScreenerData, EquityScreenerQueryParams, ) +from openbb_core.provider.utils.country_utils import Country from openbb_core.provider.utils.errors import EmptyDataError from openbb_fmp.utils.definitions import ( Countries, @@ -121,8 +122,10 @@ class FMPEquityScreenerQueryParams(EquityScreenerQueryParams): default=None, description="Filter by industry.", ) - country: Countries | None = Field( - default=None, description="Filter by country, as a two-letter country code." + country: Country | None = Field( + default=None, + description="Filter by country. Accepts ISO 3166-1 alpha-2 codes (e.g., 'US', 'DE'), " + "alpha-3 codes (e.g., 'USA'), or country names (e.g., 'United States', 'united_states').", ) exchange: Exchanges | None = Field(default=None, description="Filter by exchange.") is_etf: bool | None = Field( @@ -154,6 +157,22 @@ class FMPEquityScreenerQueryParams(EquityScreenerQueryParams): raise ValueError(f"Industry must be one of {', '.join(industries)}") return v + @field_validator("country", mode="after") + @classmethod + def _validate_country(cls, v): + """Validate country is supported by FMP.""" + if v is None: + return v + # Country stores alpha_2 in uppercase, FMP expects lowercase + country_code = v.alpha_2.lower() + valid_countries = list(Countries.__args__) + if country_code not in valid_countries: + raise ValueError( + f"Country '{v.name}' ({v.alpha_2}) is not supported by FMP. " + f"Valid options: {', '.join(sorted(valid_countries)[:20])}..." + ) + return v + class FMPEquityScreenerData(EquityScreenerData): """FMP Equity Screener Data."""