My codes runtime is getting quite long, it has to iterate maybe 30,000 times and that takes around 30 sec on my computer but longer on the clients. I'm wondering if I can get any tips to speed up the calculations. The iterative functions has to put the value as close to zero as possible and it decreases or increases until the conditions are met. I sped it up by increasing by $1 then when it gets closer to the range it increments by $0.1 for precision.
I Broke it into nodes. There's an initial node, then it checks difference of left node then difference of right node. Which ever produces a smaller difference it goes in that direction until difference is as small as possible.
//Current Node
double InitialFinalPayment = bruteforceFlexibleAmortization(0);
double intialPaymentAmount = Calc_Payment(Findper() - FindSkipNMonths(), Findnint(),
Findpv() + InterestPaid, Findfv(), Findcf(), Findpf(), Finddisc(),
Findbep()), 2);
double diffInitial = Math.Abs(intialPaymentAmount - InitialFinalPayment);
decimal runningIncrement = 1M;
double nextPayment = 0;
//Node Ahead
Double incrementOutcome = bruteforceFlexibleAmortization(runningIncrement);
Double incrementPayment = intialPaymentAmount + (double)runningIncrement;
Double diffincrement = Math.Abs(incrementPayment - incrementOutcome);
//Node Behind
Double decrementOutcome = bruteforceFlexibleAmortization(-runningIncrement);
Double decrementPayment = intialPaymentAmount - (double)runningIncrement;
Double diffdecrement = Math.Abs(decrementPayment - decrementOutcome);
if (diffincrement < diffInitial)
{
runningIncrement += 1.0M;
double nextValue = bruteforceFlexibleAmortization(runningIncrement);
nextPayment = intialPaymentAmount + (double)runningIncrement;
double diffNext = Math.Abs(nextPayment - nextValue);
while (diffNext < diffdecrement)
{
diffdecrement = diffNext;
runningIncrement += 1.0M;
nextValue = bruteforceFlexibleAmortization(runningIncrement);
nextPayment = intialPaymentAmount + (double)runningIncrement;
diffNext = Math.Abs(nextPayment - nextValue);
}
diffincrement = diffNext;
runningIncrement -= 0.01M;
nextValue = bruteforceFlexibleAmortization(runningIncrement);
nextPayment = intialPaymentAmount + (double)runningIncrement;
diffNext = Math.Abs(nextPayment - nextValue);
while (diffNext < diffincrement)
{
diffincrement = diffNext;
runningIncrement -= 0.01M;
nextValue = bruteforceFlexibleAmortization(runningIncrement);
nextPayment = intialPaymentAmount + (double)runningIncrement;
diffNext = Math.Abs(nextPayment - nextValue);
}
return nextPayment + (double)0.01M;
}
else if (diffdecrement < diffInitial)
{
runningIncrement += 1.0M;
double nextValue = bruteforceFlexibleAmortization(-runningIncrement);
nextPayment = intialPaymentAmount - (double)runningIncrement;
double diffNext = Math.Abs(nextPayment - nextValue);
while (diffNext < diffdecrement)
{
diffdecrement = diffNext;
runningIncrement += 1.0M;
nextValue = bruteforceFlexibleAmortization(-runningIncrement);
nextPayment = intialPaymentAmount - (double)runningIncrement;
diffNext = Math.Abs(nextPayment - nextValue);
}
diffincrement = diffNext;
runningIncrement -= 0.01M;
nextValue = bruteforceFlexibleAmortization(-runningIncrement);
nextPayment = intialPaymentAmount - (double)runningIncrement;
diffNext = Math.Abs(nextPayment - nextValue);
while (diffNext < diffincrement)
{
diffincrement = diffNext;
runningIncrement -= 0.01M;
nextValue = bruteforceFlexibleAmortization(-runningIncrement);
nextPayment = intialPaymentAmount - (double)runningIncrement;
diffNext = Math.Abs(nextPayment - nextValue);
}
return nextPayment - (double)0.01M;
}
return InitialFinalPayment;
}
The only idea I have is by increasing/decreasing running increment to be a larger value and making that value smaller as it gets closer to the value. Like how it's 1 then 0.1, maybe 10 then 1 then 0.1 but it's definitely not gonna be clean code
If your bruteforceFlexibleAmortization is monotonic you should try using similar approach that's used by binary search instead of changing your input by the same value all the time.
var currentValue = 50;
var lastLower = 0;
var lastGreater = 100;
do
{
var currentResult = calculateResult(initialValue);
if(currentResult < expectedResult)
{
lastLower = currentValue;
currentValue = (currentValue + lastGreater) / 2;
}
else
{
lastGreater = currentValue;
currentValue = (currentValue + lastLower) / 2;
}
} while (Math.Abs(currentResult - expectedResult) < epsilon)
It will be a little different for you, because you need to call 2 methods, but you should get the point.
e.g. If you're trying to interpolate square root for a given n to a certain precision using your approach would be really slow. With binary-like you can get much more iterations to get close interpolation.
Related
I'm trying to write an indicator script that will plot the MACD with 2 lines in a practice trading tool.
At the moment, I'm following the formula which is using the EMA formula to calculate it.
I'm able to plot the chart. But somehow my indicator result does not have the exact same result as the one on meta trader 4 or on trading view. The indicator result on these apps is exactly the same.
I think I have missed something when I try to convert from the formula to actual code. Please help me fix it. Thank you.
Here is the part that will calculate the EMA.
/// ==================================================================
/// ======================== calculations ============================
/// ==================================================================
public void Calculate()
{
for (int i = 0; i < Bars.Length; i++){
if (i >= SlowEMA) {
MACD[i] = CalculateEMA(FastEMA, i) - CalculateEMA(SlowEMA, i);
Signal[i] = CalculateEMA_MACD(MACD, SignalEMA, i);
Histogram[i] = MACD[i] - Signal[i];
}
}
}
private double CalculateEMA(int Period, int index)
{
var currentValue = 0d;
var currentEMA = 0d;
var yesterdayEMA = 0d;
var smooth = 2d;
var multiplier = smooth / (1 + Period);
for (int i = 0; i < Period; i++){
currentValue = GetPrice(index + i - Period);
currentEMA = (currentValue * multiplier) + (yesterdayEMA * (1 - multiplier));
yesterdayEMA = currentEMA;
};
return yesterdayEMA;
}
private double CalculateEMA_MACD(double[] MACD, int Period, int index)
{
var currentValue = 0d;
var currentEMA = 0d;
var yesterdayEMA = 0d;
var smooth = 2d;
var multiplier = smooth / (1 + Period);
for (int i = 0; i < Period; i++){
currentValue = MACD[index + i - Period];
currentEMA = (currentValue * multiplier) + (yesterdayEMA * (1 - multiplier));
yesterdayEMA = currentEMA;
};
return yesterdayEMA;
}
private double GetPrice(int index)
{
Bar bar = Bars[index];
switch (Source)
{
case Sources.Close:
return bar.Close;
case Sources.Open:
return bar.Open;
case Sources.High:
return bar.High;
case Sources.Low:
return bar.Low;
case Sources.MedianPrice:
return (bar.High + bar.Low) / 2;
case Sources.TypicalPrice:
return (bar.High + bar.Low + bar.Close) / 3;
case Sources.WeightedClose:
return (bar.High + bar.Low + bar.Close + bar.Close) / 4;
}
throw new NotSupportedException("Unsupported price source type: " + Source);
}
It looks like your logic for EMA calculation is wrong. Based on your code, yesterdayEMA is always 0 and therefore right part of EMA equation is also 0.
private double CalculateEMA(int Period, int index)
{
...
var yesterdayEMA = 0D;
...
currentEMA = (currentValue * multiplier) + (yesterdayEMA * (1 - multiplier));
currentEMA = (currentValue * multiplier) + 0
...
}
You need to store yesterdayEMA outside of CalculateEMA and pass it as parameter for recursive calculation.
0 comes true in the first cycle, but yesterday EMA = current EMA; It starts to take values different from 0 in the next cycle due to its equality.
The following formula would calculate RSI for all prices. Whenever I add a new price to the array, it would have to recalculate the RSI for the entire array/all prices. Is there a way I can calculate the RSI for the new price without having to recalculate the entire thing? I want to do that because when I'm calculating this for every new candle and it has to be executed for the least possible time. If it's not possible, can you please suggest me a way to optimize it, so it executes as fast as possible. Right now, it's not so fast.
decimal[] prices = ...
Calculate(prices, 14);
public decimal[] Calculate(decimal[] price, int period)
{
var rsi = new decimal[price.Length];
decimal gain = 0m;
decimal loss = 0m;
rsi[0] = 0m;
for (int i = 1; i <= period; ++i)
{
var diff = price[i] - price[i - 1];
if (diff >= 0)
{
gain += diff;
}
else
{
loss -= diff;
}
}
decimal avrg = gain / period;
decimal avrl = loss / period;
decimal rs = gain / loss;
rsi[period] = 100m - (100m / (1m + rs));
for (int i = period + 1; i < price.Length; ++i)
{
var diff = price[i] - price[i - 1];
if (diff >= 0)
{
avrg = ((avrg * (period - 1)) + diff) / period;
avrl = (avrl * (period - 1)) / period;
}
else
{
avrl = ((avrl * (period - 1)) - diff) / period;
avrg = (avrg * (period - 1)) / period;
}
rs = avrg / avrl;
rsi[i] = 100m - (100m / (1m + rs));
}
return rsi;
}
I am reviewing for my test tomorrow.. and I've encountered a problem in my program (I need to create a program that will display the breakdown of the entered amount.. and I am having a problem with the cents...)
Console.Write("Enter amount: ");
double amt = double.Parse(Console.ReadLine());
thou = (int)amt / 1000;
change = (int)amt % 1000;
fivehun = (int)change / 500;
change = change % 500;
twohun = (int)change / 200;
change = change % 200;
hun = (int)change / 100;
change = change % 100;
fifty = (int)change / 50;
change = change % 50;
twenty = change / 20;
change = change % 20;
ten = (int)change / 10;
change = change % 10;
five = (int)change / 5;
change = change % 5;
one = (int)change / 1;
change = change % 1;
twencents = (int)(change / .25);
change = change % .25; //there was an error here.. starting here
tencents = (int)(change / .10);
change = change % .10;
fivecents = (int)(change / .05);
change = change % .05;
onecent = (int)(change / .01);
change = change % .01;
Console.WriteLine("The breakdown is as follows: ");
Console.WriteLine("Php 1000 ={0} ", thou);
Console.WriteLine("Php 500 ={0} ", fivehun);
Console.WriteLine("Php 200 ={0} ", twohun);
Console.WriteLine("Php 100 ={0} ", hun);
Console.WriteLine("Php 50 ={0} ", fifty);
Console.WriteLine("Php 20 ={0} ", twenty);
Console.WriteLine("Php 10 ={0} ", ten);
Console.WriteLine("Php 05 ={0} ", five);
Console.WriteLine("Php 01 ={0} ", one);
Console.WriteLine("Php 0.25 ={0} ", twencents);
Console.WriteLine("Php 0.10 ={0} ", tencents);
Console.WriteLine("Php 0.05 ={0} ", fivecents);
Console.WriteLine("Php 0.01 ={0} ", onecent);
Console.ReadKey();
The error said that I cannot convert double to int so I tried to convert it my casting it
change = (double) change % .25;
still an error..
Use double change = 0; instead of int change = 0;
EDITED
initially make double change = 0 and and split the input amt to 2 variables
double wholeValues = (int)amt;
double decimalValues = amt - wholeValues;
then change
thou = (int)amt / 1000;
change = (int)amt % 1000;
make it as
thou = (int)wholeValues / 1000;
change = (int)wholeValues % 1000;
Otherwise you will be removing the decimal values at this point
but you are missing a cast to int at
twenty = (int) change / 20;
modules by 1 will give the same value again, start cent calculation with the new variable decimalValues
one = (int)change / 1;
change = decimalValues * 100;
twencents = (int)(change / 25);
change = change % 25;
tencents = (int)(change / 10);
change = change % 10;
fivecents = (int)(change / 5);
change = change % 5;
if we use modules with decimal values you might sometime end up with incorrect values
for example for .30 cents, it will represent .25 cents = 1, .05 cents = 0,
.01 cents= 4
finally got it!
int thou, fivehun, twohun, hun, fifty, twenty, ten, five, one;
double change = 0; // added this one as suggested
Console.Write("Enter amount: ");
double amt = double.Parse(Console.ReadLine());
thou = (int)amt / 1000;
change = amt % 1000; //remove the int (change should be double)
fivehun = (int)change / 500;
change = change % 500;
twohun = (int)change / 200;
change = change % 200;
hun = (int)change / 100;
change = change % 100;
fifty = (int)change / 50;
change = change % 50;
twenty = (int) change / 20; //added int here
change = change % 20;
ten = (int)change / 10;
change = change % 10;
five = (int)change / 5;
change = change % 5;
one = (int)change / 1;
change = change % 1;
int twencents = (int)(change / 0.25);
change = change % 0.25;
int tencents = (int)(change / 0.10);
change = change % 0.10;
int fivecents = (int)(change / 0.05);
change = change % 0.05;
int onecent = (int)(change / 0.01);
change = change % 0.01;
I compute Pearson correlation (average user/item rating) many times, using my current code performance is very bad:
public double ComputeCorrelation(double[] x, double[] y, double[] meanX, double[] meanY)
{
if (x.Length != y.Length)
throw new ArgumentException("values must be the same length");
double sumNum = 0;
double sumDenom = 0;
double denomX = 0;
double denomY = 0;
for (int a = 0; a < x.Length; a++)
{
sumNum += (x[a] - meanX[a]) * (y[a] - meanY[a]);
denomX += Math.Pow(x[a] - meanX[a], 2);
denomY += Math.Pow(y[a] - meanY[a], 2);
}
var sqrtDenomX = Math.Sqrt(denomX);
var sqrtDenomY = Math.Sqrt(denomY);
if (sqrtDenomX == 0 || sqrtDenomY == 0) return 0;
sumDenom = Math.Sqrt(denomX) * Math.Sqrt(denomY);
var correlation = sumNum / sumDenom;
return correlation;
}
I am using standard Pearson correlation with MathNet.Numerics, but this is modification of standard and it's not possible to use it. Is there a way to speed it up? How can it be optimizied regarding to time complexity?
Adding some on MSE answer -- changing Pow(x,2) to diff*diff is definitely something you want to do, you may also want to avoid unnecessary bound-checking in your inner-most loop. This may be done using pointers in C#.
Could be done this way:
public unsafe double ComputeCorrelation(double[] x, double[] y, double[] meanX, double[] meanY)
{
if (x.Length != y.Length)
throw new ArgumentException("values must be the same length");
double sumNum = 0;
double sumDenom = 0;
double denomX = 0;
double denomY = 0;
double diffX;
double diffY;
int len = x.Length;
fixed (double* xptr = &x[0], yptr = &y[0], meanXptr = &meanX[0], meanYptr = &meanY[0])
{
for (int a = 0; a < len; a++)
{
diffX = (xptr[a] - meanXptr[a]);
diffY = (yptr[a] - meanYptr[a]);
sumNum += diffX * diffY;
denomX += diffX * diffX;
denomY += diffY * diffY;
}
}
var sqrtDenomX = Math.Sqrt(denomX);
var sqrtDenomY = Math.Sqrt(denomY);
if (sqrtDenomX == 0 || sqrtDenomY == 0) return 0;
sumDenom = sqrtDenomX * sqrtDenomY;
var correlation = sumNum / sumDenom;
return correlation;
}
The best way to solve your performance problems is probably to avoid computing as many correlations, if possible. If you are using the correlations as part of another computation, it may be possible to use math to remove the need for some of them.
You should also consider whether you will be able to use the square of the Pearson correlation instead of the Pearson correlation itself. That way, you can save your calls to Math.Sqrt(), which are usually quite expensive.
If you do need to take the square root, you should use sqrtDenomX and sqrtDenomY again, rather than recompute the square roots.
The only possible optimizations that I see in your code are in the following code, if you are still looking for better performance then you may want use SIMD vectorization. It will allow you to use the full computation power of the CPU
public double ComputeCorrelation(double[] x, double[] y, double[] meanX, double[] meanY)
{
if (x.Length != y.Length)
throw new ArgumentException("values must be the same length");
double sumNum = 0;
double sumDenom = 0;
double denomX = 0;
double denomY = 0;
double diffX;
double diffY;
for (int a = 0; a < x.Length; a++)
{
diffX = (x[a] - meanX[a]);
diffY = (y[a] - meanY[a]);
sumNum += diffX * diffY;
denomX += diffX * diffX;
denomY += diffY * diffY;
}
var sqrtDenomX = Math.Sqrt(denomX);
var sqrtDenomY = Math.Sqrt(denomY);
if (sqrtDenomX == 0 || sqrtDenomY == 0) return 0;
sumDenom = sqrtDenomX * sqrtDenomY;
var correlation = sumNum / sumDenom;
return correlation;
}
I am trying to convert a C++ class to C# and in the process learn something of C++. I had never run into a vector<> before and my understanding is this is like a List<> function in C#. During the conversion of the class I re-wrote the code using List futures_price = New List(Convert.ToInt32(no_steps) + 1);. As soon as I run the code, I get a "Index was out of range" error.
Having looked around on SOF, I believe the issue is regarding the parameter being out of index range relating to this, but I do not see a simple solution to solve this with the below code.
In particular, this is the line that is triggering the error: futures_prices[0] = spot_price * Math.Pow(d, no_steps);
Below is the full code:
public double futures_option_price_call_american_binomial(double spot_price, double option_strike, double r, double sigma, double time, double no_steps)
{
//double spot_price, // price futures contract
//double option_strike, // exercise price
//double r, // interest rate
//double sigma, // volatility
//double time, // time to maturity
//int no_steps
List<double> futures_prices = new List<double>(Convert.ToInt32(no_steps) + 1);
//(no_steps+1);
//double call_values = (no_steps+1);
List<double> call_values = new List<double>(Convert.ToInt32(no_steps) + 1);
double t_delta = time/no_steps;
double Rinv = Math.Exp(-r*(t_delta));
double u = Math.Exp(sigma * Math.Sqrt(t_delta));
double d = 1.0/u;
double uu= u*u;
double pUp = (1-d)/(u-d); // note how probability is calculated
double pDown = 1.0 - pUp;
futures_prices[0] = spot_price * Math.Pow(d, no_steps);
int i;
for (i=1; i<=no_steps; ++i) futures_prices[i] = uu*futures_prices[i-1]; // terminal tree nodes
for (i=0; i<=no_steps; ++i) call_values[i] = Math.Max(0.0, (futures_prices[i]-option_strike));
for (int step = Convert.ToInt32(no_steps) - 1; step >= 0; --step)
{
for (i = 0; i <= step; ++i)
{
futures_prices[i] = d * futures_prices[i + 1];
call_values[i] = (pDown * call_values[i] + pUp * call_values[i + 1]) * Rinv;
call_values[i] = Math.Max(call_values[i], futures_prices[i] - option_strike); // check for exercise
};
};
return call_values[0];
}
Here is the original source in C++:
double futures_option_price_call_american_binomial(const double& F, // price futures contract
const double& K, // exercise price
const double& r, // interest rate
const double& sigma, // volatility
const double& time, // time to maturity
const int& no_steps) { // number of steps
vector<double> futures_prices(no_steps+1);
vector<double> call_values (no_steps+1);
double t_delta= time/no_steps;
double Rinv = exp(-r*(t_delta));
double u = exp(sigma*sqrt(t_delta));
double d = 1.0/u;
double uu= u*u;
double pUp = (1-d)/(u-d); // note how probability is calculated
double pDown = 1.0 - pUp;
futures_prices[0] = F*pow(d, no_steps);
int i;
for (i=1; i<=no_steps; ++i) futures_prices[i] = uu*futures_prices[i-1]; // terminal tree nodes
for (i=0; i<=no_steps; ++i) call_values[i] = max(0.0, (futures_prices[i]-K));
for (int step=no_steps-1; step>=0; --step) {
for (i=0; i<=step; ++i) {
futures_prices[i] = d*futures_prices[i+1];
call_values[i] = (pDown*call_values[i]+pUp*call_values[i+1])*Rinv;
call_values[i] = max(call_values[i], futures_prices[i]-K); // check for exercise
};
};
return call_values[0];
};
A List<double> starts out empty until you add items to it. (passing the constructor argument just sets the capacity, preventing costly resizes)
You can't access [0] until you Add() it.
To use it the way you are, use an array instead.
As SLaks says, it's better to use an Array in this situation. C# lists are filled with Add method and values are removed through Remove method... this would be more complicated and memory/performance expensive as you are also replacing values.
public Double FuturesOptionPriceCallAmericanBinomial(Double spotPrice, Double optionStrike, Double r, Double sigma, Double time, Double steps)
{
// Avoid calling Convert multiple times as it can be quite performance expensive.
Int32 stepsInteger = Convert.ToInt32(steps);
Double[] futurePrices = new Double[(stepsInteger + 1)];
Double[] callValues = new Double[(stepsInteger + 1)];
Double tDelta = time / steps;
Double rInv = Math.Exp(-r * (tDelta));
Double u = Math.Exp(sigma * Math.Sqrt(tDelta));
Double d = 1.0 / u;
Double uu = u * u;
Double pUp = (1 - d) / (u - d);
Double pDown = 1.0 - pUp;
futurePrices[0] = spotPrice * Math.Pow(d, steps);
for (Int32 i = 1; i <= steps; ++i)
futurePrices[i] = uu * futurePrices[(i - 1)];
for (Int32 i = 0; i <= steps; ++i)
callValues[i] = Math.Max(0.0, (futurePrices[i] - optionStrike));
for (Int32 step = stepsInteger - 1; step >= 0; --step)
{
for (Int32 i = 0; i <= step; ++i)
{
futurePrices[i] = d * futurePrices[(i + 1)];
callValues[i] = ((pDown * callValues[i]) + (pUp * callValues[i + 1])) * rInv;
callValues[i] = Math.Max(callValues[i], (futurePrices[i] - option_strike));
}
}
return callValues[0];
}