Trading view vs Binance DMI calculation? - php

I'm trying to calculate the directional movement indicator for 5m interval using the API of Binance. I'm using 288 values of "High", "Open" and "Close" and
I'm calculating the True range and then the Average True Range (ATR) with a simple moving average of a window with 14 values. I'm using the same Simple Moving average technique
for the calculation of the +DI, -DI and the ADX, but the values that I get don't match the ones that are shown in trading view for the DMI. I have also tried using an
exponential moving average the ATR, the +Di and the -DI, but I still don't get matching values. I have also noticed that the DMI of Binance and Trading view do not match.
Do you know which smoothing techinique is used by the DMI of trading view?
$url = 'https://api.binance.com/api/v3/klines?symbol=BNBBTC&interval=5m&limit=288';
$candles = file_get_contents($url);
$candles = json_decode($candles, true);
$arr_results = array();
$high = array();
$low = array();
$close_arr = array();
$average = array();
for($i= 0; $i < sizeof($candles); $i++){
array_push($high, $candles[$i][2]);
array_push($low, $candles[$i][3]);
array_push($close_arr, $candles[$i][4]);
$av = ($candles[$i][2] + $candles[$i][3]) /2;
array_push($average, $av);
}
$plus_di = array_pop(trader_plus_di($high, $low, $close_arr, 14));
$minus_di = array_pop(trader_minus_di($high, $low, $close_arr, 14));
$adx = array_pop(trader_adx ($high, $low, $close_arr, 14));

To calculate the ATR, you need to smooth the TR (True Range) according to the following method :
Take a smoothing period nbCandles (nbCandles=14 candles typically), then:
First ATR value: ATR(1) = Sum{TR(1 -> nbCandles)} (i.e you sum the nbCandles first values of the TR to get your first value of the ATR) - If nbCandles = 14 then your first ATR value will be the sum of the first 14 values of TR.
Then, for the following ATR values, you use the following formula:
ATR(i) = ATR(i-1) - ATR(i-1)/nbCandles + TR(i)
Here is an example (based on 30 1 minutes candles historical record and 14 as the smoothing factor (number of candles used for smoothing)) :
Binance BTCUSDT 1m

Related

Find all combinations of x numbers where they sum to Y

I'm trying to write this solution in PHP.
Inputs:
number of numbers = x
smallest number = 1
sum of numbers = y
I'm not dealing with very large numbers, largest x is approximatly 50, largest y is approximatly 80.
rules: Within each set of numbers, the number proceeding the previous must be equal to or greater.
For example
x = 3
min = 1
y = 6
solution:
(1,1,4),(1,2,3)
note that (3,2,1) isn't a solution as they are in descending order.
This is easily solved via recursion. The time complexity though will be high. For a better (but slightly more complex solution) use dynamic programming.
Here's the idea:
If the size of the set is 1 then the only possible solution is the desired sum.
If the set is larger than one then you can merge a number X between the minimum and the desired sum with a set of numbers which add up to the desired sum minus X.
function tuplesThatSumUpTo($desiredSum, $minimumNumber, $setSize) {
$tuples = [];
if ($setSize <= 1) {
return [ [ $desiredSum ] ]; //A set of sets of size 1 e.g. a set of the desired sum
}
for ($i = $minimumNumber;$i < $desiredSum;$i++) {
$partial = tuplesThatSumUpTo($desiredSum-$i, $minimumNumber,$setSize-1);
$tuples = array_merge($tuples, array_map(function ($tuple) use ($i) {
$res = array_merge([$i], $tuple);
sort($res);
return $res;
},$partial));
}
return array_unique($tuples,SORT_REGULAR);
}
See it run:
http://sandbox.onlinephpfunctions.com/code/1b0e507f8c2fcf06f4598005bf87ee98ad2505b3
The dynamic programming approach would have you instead hold an array of sets with partial sums and refer back to it to fill in what you need later on.

calculating cumulative average growth rate in PHP

I am trying to compare the performance of 2 investments by calculating back the cumulative average growth rate.
I have found this formula which works perfectly in excel but I cannot get it to work in php...it simply returns '0' every time:
CAGR = (Xn/X0)^(1/t) - 1
where:
Xn = current market value of portfolio
X0 = initial portfolio's value
t = number of years
Any help is greatly appreciated. Thanks.
You can try Exponential expression function pow()
CAGR = pow(($Xn/$X0),(1/$t)) - 1
This should works:
$Xn = 123; // current market value of portfolio
$X0 = 50; // initial portfolio's value
$t = 5; // number of years
$CAGR = pow( ($Xn / $X0), (1 / $t) ) - 1 ;
print($CAGR);

Get result based on probability distribution

In a browser game we have items that occur based on their probabilities.
P(i1) = 0.8
P(i2) = 0.45
P(i3) = 0.33
P(i4) = 0.01
How do we implement a function in php that returns a random item based on its probability chance?
edit
The items have a property called rarity which varies from 1 to 100 and represents the probability to occcur. The item that occurs is chosen from a set of all items of a certain type. (e.x the given example above represents all artifacts tier 1)
I don't know if its the best solution but when I had to solve this a while back this is what I found:
Function taken from this blog post:
// Given an array of values, and weights for those values (any positive int)
// it will select a value randomly as often as the given weight allows.
// for example:
// values(A, B, C, D)
// weights(30, 50, 100, 25)
// Given these values C should come out twice as often as B, and 4 times as often as D.
function weighted_random($values, $weights){
$count = count($values);
$i = 0;
$n = 0;
$num = mt_rand(0, array_sum($weights));
while($i < $count){
$n += $weights[$i];
if($n >= $num){
break;
}
$i++;
}
return $values[$i];
}
Example call:
$values = array('A','B','C');
$weights = array(1,50,100);
$weighted_value = weighted_random($values, $weights);
It's somewhat unwieldy as obviously the values and weights need to be supplied separately but this could probably be refactored to suit your needs.
Tried to understand how Bulk's function works, and here is how I understand based on Benjamin Kloster answer:
https://softwareengineering.stackexchange.com/questions/150616/return-random-list-item-by-its-weight
Generate a random number n in the range of 0 to sum(weights), in this case $num so lets say from this: weights(30, 50, 100, 25).
Sum is 205.
Now $num has to be 0-30 to get A,
30-80 to get B
80-180 to get C
and 180-205 to get D
While loop finds in which interval the $num falls.

Calculate average without being thrown by strays

I am trying to calculate an average without being thrown off by a small set of far off numbers (ie, 1,2,1,2,3,4,50) the single 50 will throw off the entire average.
If I have a list of numbers like so:
19,20,21,21,22,30,60,60
The average is 31
The median is 30
The mode is 21 & 60 (averaged to 40.5)
But anyone can see that the majority is in the range 19-22 (5 in, 3 out) and if you get the average of just the major range it's 20.6 (a big difference than any of the numbers above)
I am thinking that you can get this like so:
c+d-r
Where c is the count of a numbers, d is the distinct values, and r is the range. Then you can apply this to all the possble ranges, and the highest score is the omptimal range to get an average from.
For example 19,20,21,21,22 would be 5 numbers, 4 distinct values, and the range is 3 (22 - 19). If you plug this into my equation you get 5+4-3=6
If you applied this to the entire number list it would be 8+6-41=-27
I think this works pretty good, but I have to create a huge loop to test against all possible ranges. In just my small example there are 21 possible ranges:
19-19, 19-20, 19-21, 19-22, 19-30, 19-60, 20-20, 20-21, 20-22, 20-30, 20-60, 21-21, 21-22, 21-30, 21-60, 22-22, 22-30, 22-60, 30-30, 30-60, 60-60
I am wondering if there is a more efficient way to get an average like this.
Or if someone has a better algorithm all together?
You might get some use out of standard deviation here, which basically measures how concentrated the data points are. You can define an outlier as anything more than 1 standard deviation (or whatever other number suits you) from the average, throw them out, and calculate a new average that doesn't include them.
Here's a pretty naive implementation that you could fix up for your own needs. I purposely kept it pretty verbose. It's based on the five-number-summary often used to figure these things out.
function get_median($arr) {
sort($arr);
$c = count($arr) - 1;
if ($c%2) {
$b = round($c/2);
$a = $b-1;
return ($arr[$b] + $arr[$a]) / 2 ;
} else {
return $arr[($c/2)];
}
}
function get_five_number_summary($arr) {
sort($arr);
$c = count($arr) - 1;
$fns = array();
if ($c%2) {
$b = round($c/2);
$a = $b-1;
$lower_quartile = array_slice($arr, 1, $a-1);
$upper_quartile = array_slice($arr, $b+1, count($lower_quartile));
$fns = array($arr[0], get_median($lower_quartile), get_median($arr), get_median($upper_quartile), $arr[$c-1]);
return $fns;
}
else {
$b = round($c/2);
$a = $b-1;
$lower_quartile = array_slice($arr, 1, $a);
$upper_quartile = array_slice($arr, $b+1, count($lower_quartile));
$fns = array($arr[0], get_median($lower_quartile), get_median($arr), get_median($upper_quartile), $arr[$c-1]);
return $fns;
}
}
function find_outliers($arr) {
$fns = get_five_number_summary($arr);
$interquartile_range = $fns[3] - $fns[1];
$low = $fns[1] - $interquartile_range;
$high = $fns[3] + $interquartile_range;
foreach ($arr as $v) {
if ($v > $high || $v < $low)
echo "$v is an outlier<br>";
}
}
//$numbers = array( 19,20,21,21,22,30,60 ); // 60 is an outlier
$numbers = array( 1,230,239,331,340,800); // 1 is an outlier, 800 is an outlier
find_outliers($numbers);
Note that this method, albeit much simpler to implement than standard deviation, will not find the two 60 outliers in your example, but it works pretty well. Use the code for whatever, hopefully it's useful!
To see how the algorithm works and how I implemented it, go to: http://www.mathwords.com/o/outlier.htm
This, of course, doesn't calculate the final average, but it's kind of trivial after you run find_outliers() :P
Why don't you use the median? It's not 30, it's 21.5.
You could put the values into an array, sort the array, and then find the median, which is usually a better number than the average anyway because it discounts outliers automatically, giving them no more weight than any other number.
You might sort your numbers, choose your preferred subrange (e.g., the middle 90%), and take the mean of that.
There is no one true answer to your question, because there are always going to be distributions that will give you a funny answer (e.g., consider a biased bi-modal distribution). This is why may statistics are often presented using box-and-whisker diagrams showing mean, median, quartiles, and outliers.

PHP: find two or more numbers from a list of numbers that add up towards a given amount

I am trying to create a little php script that can make my life a bit easier.
Basically, I am going to have 21 text fields on a page where I am going to input 20 different numbers. In the last field I will enter a number let's call it the TOTAL AMOUNT. All I want the script to do is to point out which numbers from the 20 fields added up will come up to TOTAL AMOUNT.
Example:
field1 = 25.23
field2 = 34.45
field3 = 56.67
field4 = 63.54
field5 = 87.54
....
field20 = 4.2
Total Amount = 81.90
Output: field1 + fields3 = 81.90
Some of the fields might have 0 as value because sometimes I only need to enter 5-15 fields and the maximum will be 20.
If someone can help me out with the php code for this, will be greatly appreciated.
If you look at oezis algorithm one drawback is immediately clear: It spends very much time summing up numbers which are already known not to work. (For example if 1 + 2 is already too big, it doesn't make any sense to try 1 + 2 + 3, 1 + 2 + 3 + 4, 1 + 2 + 3 + 4 + 5, ..., too.)
Thus I have written an improved version. It does not use bit magic, it makes everything manual. A drawback is, that it requires the input values to be sorted (use rsort). But that shouldn't be a big problem ;)
function array_sum_parts($vals, $sum){
$solutions = array();
$pos = array(0 => count($vals) - 1);
$lastPosIndex = 0;
$currentPos = $pos[0];
$currentSum = 0;
while (true) {
$currentSum += $vals[$currentPos];
if ($currentSum < $sum && $currentPos != 0) {
$pos[++$lastPosIndex] = --$currentPos;
} else {
if ($currentSum == $sum) {
$solutions[] = array_slice($pos, 0, $lastPosIndex + 1);
}
if ($lastPosIndex == 0) {
break;
}
$currentSum -= $vals[$currentPos] + $vals[1 + $currentPos = --$pos[--$lastPosIndex]];
}
}
return $solutions;
}
A modified version of oezis testing program (see end) outputs:
possibilities: 540
took: 3.0897309780121
So it took only 3.1 seconds to execute, whereas oezis code executed 65 seconds on my machine (yes, my machine is very slow). That's more than 20 times faster!
Furthermore you may notice, that my code found 540 instead of 338 possibilities. This is because I adjusted the testing program to use integers instead of floats. Direct floating point comparison is rarely the right thing to do, this is a great example why: You sometimes get 59.959999999999 instead of 59.96 and thus the match will not be counted. So, if I run oezis code with integers it finds 540 possibilities, too ;)
Testing program:
// Inputs
$n = array();
$n[0] = 6.56;
$n[1] = 8.99;
$n[2] = 1.45;
$n[3] = 4.83;
$n[4] = 8.16;
$n[5] = 2.53;
$n[6] = 0.28;
$n[7] = 9.37;
$n[8] = 0.34;
$n[9] = 5.82;
$n[10] = 8.24;
$n[11] = 4.35;
$n[12] = 9.67;
$n[13] = 1.69;
$n[14] = 5.64;
$n[15] = 0.27;
$n[16] = 2.73;
$n[17] = 1.63;
$n[18] = 4.07;
$n[19] = 9.04;
$n[20] = 6.32;
// Convert to Integers
foreach ($n as &$num) {
$num *= 100;
}
$sum = 57.96 * 100;
// Sort from High to Low
rsort($n);
// Measure time
$start = microtime(true);
echo 'possibilities: ', count($result = array_sum_parts($n, $sum)), '<br />';
echo 'took: ', microtime(true) - $start;
// Check that the result is correct
foreach ($result as $element) {
$s = 0;
foreach ($element as $i) {
$s += $n[$i];
}
if ($s != $sum) echo '<br />FAIL!';
}
var_dump($result);
sorry for adding a new answer, but this is a complete new solution to solve all problems of life, universe and everything...:
function array_sum_parts($n,$t,$all=false){
$count_n = count($n); // how much fields are in that array?
$count = pow(2,$count_n); // we need to do 2^fields calculations to test all possibilities
# now i want to look at every number from 1 to $count, where the number is representing
# the array and add up all array-elements which are at positions where my actual number
# has a 1-bit
# EXAMPLE:
# $i = 1 in binary mode 1 = 01 i'll use ony the first array-element
# $i = 10 in binary mode 10 = 1010 ill use the secont and the fourth array-element
# and so on... the number of 1-bits is the amount of numbers used in that try
for($i=1;$i<=$count;$i++){ // start calculating all possibilities
$total=0; // sum of this try
$anzahl=0; // counter for 1-bits in this try
$k = $i; // store $i to another variable which can be changed during the loop
for($j=0;$j<$count_n;$j++){ // loop trough array-elemnts
$total+=($k%2)*$n[$j]; // add up if the corresponding bit of $i is 1
$anzahl+=($k%2); // add up the number of 1-bits
$k=$k>>1; //bit-shift to the left for looking at the next bit in the next loop
}
if($total==$t){
$loesung[$i] = $anzahl; // if sum of this try is the sum we are looking for, save this to an array (whith the number of 1-bits for sorting)
if(!$all){
break; // if we're not looking for all solutions, make a break because the first one was found
}
}
}
asort($loesung); // sort all solutions by the amount of numbers used
// formating the solutions to getting back the original array-keys (which shoud be the return-value)
foreach($loesung as $val=>$anzahl){
$bit = strrev(decbin($val));
$total=0;
$ret_this = array();
for($j=0;$j<=strlen($bit);$j++){
if($bit[$j]=='1'){
$ret_this[] = $j;
}
}
$ret[]=$ret_this;
}
return $ret;
}
// Inputs
$n[0]=6.56;
$n[1]=8.99;
$n[2]=1.45;
$n[3]=4.83;
$n[4]=8.16;
$n[5]=2.53;
$n[6]=0.28;
$n[7]=9.37;
$n[8]=0.34;
$n[9]=5.82;
$n[10]=8.24;
$n[11]=4.35;
$n[12]=9.67;
$n[13]=1.69;
$n[14]=5.64;
$n[15]=0.27;
$n[16]=2.73;
$n[17]=1.63;
$n[18]=4.07;
$n[19]=9.04;
$n[20]=6.32;
// Output
$t=57.96;
var_dump(array_sum_parts($n,$t)); //returns one possible solution (fuc*** fast)
var_dump(array_sum_parts($n,$t,true)); // returns all possible solution (relatively fast when you think of all the needet calculations)
if you don't use the third parameter, it returns the best (whith the least amount numbers used) solution as array (whith keys of the input-array) - if you set the third parameter to true, ALL solutions are returned (for testing, i used the same numbers as zaf in his post - there are 338 solutions in this case, found in ~10sec on my machine).
EDIT:
if you get all, you get the results ordered by which is "best" - whithout this, you only get the first found solution (which isn't necessarily the best).
EDIT2:
to forfil the desire of some explanation, i commented the essential parts of the code . if anyone needs more explanation, please ask
1. Check and eliminate fields values more than 21st field
2. Check highest of the remaining, Add smallest,
3. if its greater than 21st eliminate highest (iterate this process)
4. If lower: Highest + second Lowest, if equal show result.
5. if higher go to step 7
6. if lower go to step 4
7. if its lower than add second lowest, go to step 3.
8. if its equal show result
This is efficient and will take less execution time.
Following method will give you an answer... almost all of the time. Increase the iterations variable to your taste.
<?php
// Inputs
$n[1]=8.99;
$n[2]=1.45;
$n[3]=4.83;
$n[4]=8.16;
$n[5]=2.53;
$n[6]=0.28;
$n[7]=9.37;
$n[8]=0.34;
$n[9]=5.82;
$n[10]=8.24;
$n[11]=4.35;
$n[12]=9.67;
$n[13]=1.69;
$n[14]=5.64;
$n[15]=0.27;
$n[16]=2.73;
$n[17]=1.63;
$n[18]=4.07;
$n[19]=9.04;
$n[20]=6.32;
// Output
$t=57.96;
// Let's try to do this a million times randomly
// Relax, thats less than a blink
$iterations=1000000;
while($iterations-->0){
$z=array_rand($n, mt_rand(2,20));
$total=0;
foreach($z as $x) $total+=$n[$x];
if($total==$t)break;
}
// If we did less than a million times we have an answer
if($iterations>0){
$total=0;
foreach($z as $x){
$total+=$n[$x];
print("[$x] + ". $n[$x] . " = $total<br/>");
}
}
?>
One solution:
[1] + 8.99 = 8.99
[4] + 8.16 = 17.15
[5] + 2.53 = 19.68
[6] + 0.28 = 19.96
[8] + 0.34 = 20.3
[10] + 8.24 = 28.54
[11] + 4.35 = 32.89
[13] + 1.69 = 34.58
[14] + 5.64 = 40.22
[15] + 0.27 = 40.49
[16] + 2.73 = 43.22
[17] + 1.63 = 44.85
[18] + 4.07 = 48.92
[19] + 9.04 = 57.96
A probably inefficient but simple solution with backtracking
function subset_sums($a, $val, $i = 0) {
$r = array();
while($i < count($a)) {
$v = $a[$i];
if($v == $val)
$r[] = $v;
if($v < $val)
foreach(subset_sums($a, $val - $v, $i + 1) as $s)
$r[] = "$v $s";
$i++;
}
return $r;
}
example
$ns = array(1, 2, 6, 7, 11, 5, 8, 9, 3);
print_r(subset_sums($ns, 11));
result
Array
(
[0] => 1 2 5 3
[1] => 1 2 8
[2] => 1 7 3
[3] => 2 6 3
[4] => 2 9
[5] => 6 5
[6] => 11
[7] => 8 3
)
i don't think the answer isn't as easy as nik mentioned. let's ay you have the following numbers:
1 2 3 6 8
looking for an amount of 10
niks solution would do this (if i understand it right):
1*8 = 9 = too low
adding next lowest (2) = 11 = too high
now he would delete the high number and start again taking the new highest
1*6 = 7 = too low
adding next lowest (2) = 9 = too low
adding next lowest (3) = 12 = too high
... and so on, where the perfect answer would simply
be 8+2 = 10... i think the only solution is trying every possible combination of
numbers and stop if the amaunt you are looking for is found (or realy calculate all, if there are different solutions and save which one has used least numbers).
EDIT: realy calculating all possible combiations of 21 numbers will end up in realy, realy, realy much calculations - so there must be any "intelligent" solution for adding numbers in a special order (lik that one in niks post - with some improvements, maybe that will bring us to a reliable solution)
Without knowing if this is a homework assignment or not, I can give you some pseudo code as a hint for a possible solution, note the solution is not very efficient, more of a demonstration.
Hint:
Compare each field value to all field value and at each iteration check if their sum is equal to TOTAL_AMOUNT.
Pseudo code:
for i through field 1-20
for j through field 1-20
if value of i + value of j == total_amount
return i and j
Update:
What you seem to be having is the Subset sum problem, given within the Wiki link is pseudo code for the algorithm which might help point you in the right direction.

Categories