MT5APIMath.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. //+------------------------------------------------------------------+
  2. //| MetaTrader 5 API |
  3. //| Copyright 2000-2019, MetaQuotes Software Corp. |
  4. //| http://www.metaquotes.net |
  5. //+------------------------------------------------------------------+
  6. #pragma once
  7. #include <string.h>
  8. #include <math.h>
  9. //+------------------------------------------------------------------+
  10. //| Volume constants |
  11. //+------------------------------------------------------------------+
  12. #define MTAPI_VOLUME_DIV (10000.0)
  13. #define MTAPI_VOLUME_DIGITS (4)
  14. #define MTAPI_VOLUME_MAX ((UINT64)10000000000)
  15. //+------------------------------------------------------------------+
  16. //| Volume with extended accuracy constants |
  17. //+------------------------------------------------------------------+
  18. #define MTAPI_VOLUME_EXT_DIV (100000000.0)
  19. #define MTAPI_VOLUME_EXT_DIGITS (8)
  20. #define MTAPI_VOLUME_EXT_MAX ((UINT64)10000000000000000000)
  21. //+------------------------------------------------------------------+
  22. //| Price constants |
  23. //+------------------------------------------------------------------+
  24. #define MTAPI_PRICE_MAX (100000000)
  25. #define MTAPI_PRICE_DIGITS_MAX (11)
  26. //+------------------------------------------------------------------+
  27. //| Mathematical operations |
  28. //+------------------------------------------------------------------+
  29. class SMTMath
  30. {
  31. private:
  32. static const double s_decimal[16];
  33. static const double s_fdecimal[16];
  34. static const double s_rounder_math;
  35. public:
  36. //--- common functions
  37. static double DecPow(INT digits);
  38. //--- price functions
  39. static double PriceNormalize(const double price,UINT digits);
  40. static INT64 PriceToInt(const double price,const UINT digits);
  41. static UINT64 PriceToIntPos(const double price,const UINT digits);
  42. static double PriceToDouble(const INT64 value,UINT digits);
  43. //--- volume functions
  44. static UINT64 VolumeToInt(const double volume);
  45. static double VolumeToDouble(const UINT64 volume);
  46. static double VolumeToSize(const UINT64 volume,double contract_size);
  47. static UINT64 VolumeFromSize(const double size,double contract_size);
  48. static UINT64 VolumeFromVolumeExt(const UINT64 volume);
  49. //--- volume with extended accuracy functions
  50. static UINT64 VolumeExtToInt(const double volume);
  51. static double VolumeExtToDouble(const UINT64 volume);
  52. static double VolumeExtToSize(const UINT64 volume,double contract_size);
  53. static UINT64 VolumeExtFromSize(const double size,double contract_size);
  54. static UINT64 VolumeExtFromVolume(const UINT64 volume);
  55. //--- money digits
  56. static double MoneyAdd(const double left,const double right,const UCHAR digits);
  57. static bool MoneyEqual(const double left,const double right,const UCHAR digits);
  58. static UINT MoneyDigits(LPCWSTR currency);
  59. };
  60. //+------------------------------------------------------------------+
  61. //| 16 powers |
  62. //+------------------------------------------------------------------+
  63. const __declspec(selectany) double SMTMath::s_decimal[16]=
  64. {
  65. 1.0,
  66. 10.0,
  67. 100.0,
  68. 1000.0,
  69. 10000.0,
  70. 100000.0,
  71. 1000000.0,
  72. 10000000.0,
  73. 100000000.0,
  74. 1000000000.0,
  75. 10000000000.0,
  76. 100000000000.0,
  77. 1000000000000.0,
  78. 10000000000000.0,
  79. 100000000000000.0,
  80. 1000000000000000.0,
  81. };
  82. //+------------------------------------------------------------------+
  83. //| Negative 16 powers |
  84. //+------------------------------------------------------------------+
  85. const __declspec(selectany) double SMTMath::s_fdecimal[16]=
  86. {
  87. 1.0,
  88. 0.1,
  89. 0.01,
  90. 0.001,
  91. 0.0001,
  92. 0.00001,
  93. 0.000001,
  94. 0.0000001,
  95. 0.00000001,
  96. 0.000000001,
  97. 0.0000000001,
  98. 0.00000000001,
  99. 0.000000000001,
  100. 0.0000000000001,
  101. 0.00000000000001,
  102. 0.000000000000001,
  103. };
  104. //+------------------------------------------------------------------+
  105. //| Rounder constant |
  106. //+------------------------------------------------------------------+
  107. const __declspec(selectany) double SMTMath::s_rounder_math=0.5000001;
  108. //+------------------------------------------------------------------+
  109. //| Decimal power |
  110. //+------------------------------------------------------------------+
  111. inline double SMTMath::DecPow(INT digits)
  112. {
  113. //--- check sign
  114. if(digits>0 && digits<_countof(s_decimal))
  115. return(s_decimal[digits]);
  116. else
  117. if(digits<0 && -digits<_countof(s_fdecimal))
  118. return(s_fdecimal[-digits]);
  119. //--- use standard pow
  120. return(pow(10.0,digits));
  121. }
  122. //+------------------------------------------------------------------+
  123. //| Price normalization |
  124. //+------------------------------------------------------------------+
  125. inline double SMTMath::PriceNormalize(const double val,UINT digits)
  126. {
  127. double dbl_integer;
  128. //--- check digits
  129. if(digits>MTAPI_PRICE_DIGITS_MAX)
  130. digits=MTAPI_PRICE_DIGITS_MAX;
  131. //--- calculate dividers
  132. double p=s_decimal[digits];
  133. dbl_integer=double(__int64(val));
  134. double dbl_fract=(val-dbl_integer)*p;
  135. //--- check sign
  136. if(val>0) dbl_fract+=s_rounder_math;
  137. else dbl_fract-=s_rounder_math;
  138. //--- calc fractional part
  139. dbl_fract=double(__int64(dbl_fract));
  140. //--- summary
  141. return(dbl_integer+dbl_fract/p);
  142. }
  143. //+------------------------------------------------------------------+
  144. //| Price conversion from double to integer |
  145. //+------------------------------------------------------------------+
  146. inline INT64 SMTMath::PriceToInt(const double price,const UINT digits)
  147. {
  148. //--- check
  149. if(digits>MTAPI_PRICE_DIGITS_MAX || price<=0.0 || price>_I64_MAX)
  150. return(0);
  151. //--- calculate
  152. return((INT64)((price>=0.0) ? (price*s_decimal[digits]+s_rounder_math):(price*s_decimal[digits]-s_rounder_math)));
  153. }
  154. //+------------------------------------------------------------------+
  155. //| Price conversion from double to integer |
  156. //+------------------------------------------------------------------+
  157. inline UINT64 SMTMath::PriceToIntPos(const double price,const UINT digits)
  158. {
  159. //--- check
  160. if(price<=0.0)
  161. return(PriceToInt(price,digits));
  162. //--- calculate
  163. return((UINT64)(price*s_decimal[digits]+s_rounder_math));
  164. }
  165. //+------------------------------------------------------------------+
  166. //| Price conversion from integer to double |
  167. //+------------------------------------------------------------------+
  168. inline double SMTMath::PriceToDouble(const INT64 value,UINT digits)
  169. {
  170. //--- check
  171. if(digits>MTAPI_PRICE_DIGITS_MAX)
  172. digits=MTAPI_PRICE_DIGITS_MAX;
  173. //--- divide
  174. return(PriceNormalize(double(value)/s_decimal[digits],digits));
  175. }
  176. //+------------------------------------------------------------------+
  177. //| Volume conversion from double to integer |
  178. //+------------------------------------------------------------------+
  179. inline UINT64 SMTMath::VolumeToInt(const double volume)
  180. {
  181. return(PriceToIntPos(volume,MTAPI_VOLUME_DIGITS));
  182. }
  183. //+------------------------------------------------------------------+
  184. //| Volume conversion from integer to double |
  185. //+------------------------------------------------------------------+
  186. inline double SMTMath::VolumeToDouble(const UINT64 volume)
  187. {
  188. return(PriceNormalize(volume/double(MTAPI_VOLUME_DIV),MTAPI_VOLUME_DIGITS));
  189. }
  190. //+------------------------------------------------------------------+
  191. //| Volume conversion from lots to amount |
  192. //+------------------------------------------------------------------+
  193. inline double SMTMath::VolumeToSize(const UINT64 volume,double contract_size)
  194. {
  195. return(PriceNormalize(volume/double(MTAPI_VOLUME_DIV)*contract_size,MTAPI_VOLUME_DIGITS));
  196. }
  197. //+------------------------------------------------------------------+
  198. //| Volume conversion from amount to lots |
  199. //+------------------------------------------------------------------+
  200. inline UINT64 SMTMath::VolumeFromSize(const double size,double contract_size)
  201. {
  202. return((UINT64)PriceNormalize((size/contract_size)*double(MTAPI_VOLUME_DIV),0));
  203. }
  204. //+------------------------------------------------------------------+
  205. //| Volume conversion from extended accuracy volume |
  206. //+------------------------------------------------------------------+
  207. inline UINT64 SMTMath::VolumeFromVolumeExt(const UINT64 volume_ext)
  208. {
  209. return(volume_ext/10000);
  210. }
  211. //+------------------------------------------------------------------+
  212. //| Volume conversion from double to integer |
  213. //+------------------------------------------------------------------+
  214. inline UINT64 SMTMath::VolumeExtToInt(const double volume)
  215. {
  216. return(PriceToIntPos(volume,MTAPI_VOLUME_EXT_DIGITS));
  217. }
  218. //+------------------------------------------------------------------+
  219. //| Volume conversion from integer to double |
  220. //+------------------------------------------------------------------+
  221. inline double SMTMath::VolumeExtToDouble(const UINT64 volume)
  222. {
  223. return(PriceNormalize(volume/double(MTAPI_VOLUME_EXT_DIV),MTAPI_VOLUME_EXT_DIGITS));
  224. }
  225. //+------------------------------------------------------------------+
  226. //| Volume conversion from lots to amount |
  227. //+------------------------------------------------------------------+
  228. inline double SMTMath::VolumeExtToSize(const UINT64 volume,double contract_size)
  229. {
  230. return(PriceNormalize(volume/double(MTAPI_VOLUME_EXT_DIV)*contract_size,MTAPI_VOLUME_EXT_DIGITS));
  231. }
  232. //+------------------------------------------------------------------+
  233. //| Volume conversion from amount to lots |
  234. //+------------------------------------------------------------------+
  235. inline UINT64 SMTMath::VolumeExtFromSize(const double size,double contract_size)
  236. {
  237. return((UINT64)PriceNormalize((size/contract_size)*double(MTAPI_VOLUME_EXT_DIV),0));
  238. }
  239. //+------------------------------------------------------------------+
  240. //| Volume conversion to extended accuracy volume |
  241. //+------------------------------------------------------------------+
  242. inline UINT64 SMTMath::VolumeExtFromVolume(const UINT64 volume)
  243. {
  244. return(volume*10000);
  245. }
  246. //+------------------------------------------------------------------+
  247. //| Money add |
  248. //+------------------------------------------------------------------+
  249. inline double SMTMath::MoneyAdd(const double left,const double right,const UCHAR digits)
  250. {
  251. return(PriceNormalize(left+right,digits));
  252. }
  253. //+------------------------------------------------------------------+
  254. //| Money Compare |
  255. //+------------------------------------------------------------------+
  256. inline bool SMTMath::MoneyEqual(const double left,const double right,const UCHAR digits)
  257. {
  258. return(fabs(left-right)<DecPow(-(digits+1)));
  259. }
  260. //+------------------------------------------------------------------+
  261. //| Digits by currency |
  262. //+------------------------------------------------------------------+
  263. inline UINT SMTMath::MoneyDigits(LPCWSTR currency)
  264. {
  265. //--- check param
  266. if(currency)
  267. {
  268. if(_wcsicmp(currency,L"JPY")==0) return(0);
  269. if(_wcsicmp(currency,L"VND")==0) return(0);
  270. }
  271. //--- 2 digits by default
  272. return(2);
  273. }
  274. //+------------------------------------------------------------------+