openpine_vm/currency.rs
1use openpine_macros::Enum;
2use serde::{Deserialize, Serialize};
3
4/// Currency codes as per ISO 4217 standard.
5#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Enum, Serialize, Deserialize)]
6#[openpine(rename_all = "uppercase")]
7pub enum Currency {
8 /// Arab Emirates Dirham.
9 AED,
10 /// Argentine Peso.
11 ARS,
12 /// Australian Dollar.
13 AUD,
14 /// Bangladeshi Taka.
15 BDT,
16 /// Bahraini Dinar.
17 BHD,
18 /// Brazilian Real.
19 BRL,
20 /// Bitcoin.
21 BTC,
22 /// Canadian Dollar.
23 CAD,
24 /// Swiss Franc.
25 CHF,
26 /// Chilean Peso.
27 CLP,
28 /// Chinese Yuan.
29 CNY,
30 /// Colombian Peso.
31 COP,
32 /// Czech Koruna.
33 CZK,
34 /// Danish Krone.
35 DKK,
36 /// Egyptian Pound.
37 EGP,
38 /// Ether (Ethereum).
39 ETH,
40 /// Euro.
41 EUR,
42 /// British Pound Sterling.
43 GBP,
44 /// Hong Kong Dollar.
45 HKD,
46 /// Hungarian Forint.
47 HUF,
48 /// Indonesian Rupiah.
49 IDR,
50 /// Israeli New Shekel.
51 ILS,
52 /// Indian Rupee.
53 INR,
54 /// Icelandic Krona.
55 ISK,
56 /// Japanese Yen.
57 JPY,
58 /// Kenyan Shilling.
59 KES,
60 /// South Korean Won.
61 KRW,
62 /// Kuwaiti Dinar.
63 KWD,
64 /// Sri Lankan Rupee.
65 LKR,
66 /// Moroccan Dirham.
67 MAD,
68 /// Mexican Peso.
69 MXN,
70 /// Malaysian Ringgit.
71 MYR,
72 /// Nigerian Naira.
73 NGN,
74 /// Norwegian Krone.
75 NOK,
76 /// Unspecified currency.
77 NONE,
78 /// New Zealand Dollar.
79 NZD,
80 /// Peruvian Sol.
81 PEN,
82 /// Philippine Peso.
83 PHP,
84 /// Pakistani Rupee.
85 PKR,
86 /// Polish Zloty.
87 PLN,
88 /// Qatari Riyal.
89 QAR,
90 /// Romanian Leu.
91 RON,
92 /// Serbian Dinar.
93 RSD,
94 /// Russian Ruble.
95 RUB,
96 /// Saudi Riyal.
97 SAR,
98 /// Swedish Krona.
99 SEK,
100 /// Singapore Dollar.
101 SGD,
102 /// Thai Baht.
103 THB,
104 /// Tunisian Dinar.
105 TND,
106 /// Turkish Lira.
107 TRY,
108 /// New Taiwan Dollar.
109 TWD,
110 /// United States Dollar.
111 USD,
112 /// Tether.
113 USDT,
114 /// Venezuelan Bolívar.
115 VES,
116 /// Vietnamese Dong.
117 VND,
118 /// South African Rand.
119 ZAR,
120}
121
122/// Converts monetary values between currencies.
123///
124/// Used by `strategy.convert_to_account()` and
125/// `strategy.convert_to_symbol()`. The default implementation
126/// ([`IdentityCurrencyConverter`]) returns the input value unchanged, which
127/// is correct when the symbol currency equals the account currency.
128///
129/// Supply a custom implementation via
130/// [`InstanceBuilder::with_currency_converter()`](crate::InstanceBuilder::with_currency_converter) to enable cross-currency
131/// backtesting.
132#[async_trait::async_trait(?Send)]
133pub trait CurrencyConverter {
134 /// Converts `value` expressed in `from` currency to `to` currency.
135 ///
136 /// Returns `None` if the conversion is not possible (e.g. missing rate).
137 async fn convert(&self, value: f64, from: Currency, to: Currency) -> Option<f64>;
138}
139
140/// A no-op converter that returns the input value unchanged.
141///
142/// This is the default used when no custom converter is provided. It is
143/// correct as long as the symbol and account currencies are the same.
144#[derive(Debug, Clone, Copy)]
145pub struct IdentityCurrencyConverter;
146
147#[async_trait::async_trait(?Send)]
148impl CurrencyConverter for IdentityCurrencyConverter {
149 #[inline]
150 async fn convert(&self, value: f64, _from: Currency, _to: Currency) -> Option<f64> {
151 Some(value)
152 }
153}
154
155/// Returns the default (identity) currency converter.
156pub(crate) fn default_currency_converter() -> Box<dyn CurrencyConverter> {
157 Box::new(IdentityCurrencyConverter)
158}
159
160impl Currency {
161 /// Returns the currency sign/symbol.
162 pub fn sign(&self) -> &'static str {
163 match self {
164 Currency::AED => "د.إ",
165 Currency::ARS => "$",
166 Currency::AUD => "$",
167 Currency::BDT => "৳",
168 Currency::BHD => ".د.ب",
169 Currency::BRL => "R$",
170 Currency::BTC => "₿",
171 Currency::CAD => "$",
172 Currency::CHF => "Fr.",
173 Currency::CLP => "$",
174 Currency::CNY => "¥",
175 Currency::COP => "$",
176 Currency::CZK => "Kč",
177 Currency::DKK => "kr",
178 Currency::EGP => "£",
179 Currency::ETH => "Ξ",
180 Currency::EUR => "€",
181 Currency::GBP => "£",
182 Currency::HKD => "$",
183 Currency::HUF => "Ft",
184 Currency::IDR => "Rp",
185 Currency::ILS => "₪",
186 Currency::INR => "₹",
187 Currency::ISK => "kr",
188 Currency::JPY => "¥",
189 Currency::KES => "KSh",
190 Currency::KRW => "₩",
191 Currency::KWD => "د.ك",
192 Currency::LKR => "රු",
193 Currency::MAD => "د.م.",
194 Currency::MXN => "$",
195 Currency::MYR => "RM",
196 Currency::NGN => "₦",
197 Currency::NOK => "kr",
198 Currency::NONE => "",
199 Currency::NZD => "$",
200 Currency::PEN => "S/",
201 Currency::PHP => "₱",
202 Currency::PKR => "₨",
203 Currency::PLN => "zł",
204 Currency::QAR => "ر.ق",
205 Currency::RON => "lei",
206 Currency::RSD => "дин.",
207 Currency::RUB => "₽",
208 Currency::SAR => "ر.س",
209 Currency::SEK => "kr",
210 Currency::SGD => "$",
211 Currency::THB => "฿",
212 Currency::TND => "د.ت",
213 Currency::TRY => "₺",
214 Currency::TWD => "NT$",
215 Currency::USD => "$",
216 Currency::USDT => "$",
217 Currency::VES => "Bs.S.",
218 Currency::VND => "₫",
219 Currency::ZAR => "R",
220 }
221 }
222}