I have an indicator which indicate me round numbers on a specific chart in tradingview. For exemple, on US30 or NAS100 chart, the indicator draw horizontal line on round numbers ending by xx000 or xx500. Like 34 000, 34 500, 35 000, etc. My only problem is that the price of the line is not labled in the price scale. first picture is the actual indicator. Second is how I want it to look with the label at the right scale highlighted + the number ending in xx500 in blue + number ending by xx000 in pink.
image #1
image #2
I anybody able to make me the code line to make it work please?
Here is the code in the actual version:
//#version=5
indicator('LVL', overlay=true)
var levels = input(5, title='Number of levels')
var lineColor = input(color.rgb(255, 00, 255), 'Line color')
var lineWidth = input(1, title='Line width')
var spacing = if syminfo.ticker == 'XAUUSD'
25000
else if syminfo.ticker == 'XAGUSD'
250000
else if syminfo.ticker == 'SPX500USD'
500
else if syminfo.ticker == 'NAS100USD'
5000
else if syminfo.ticker == 'US30USD'
5000
else if syminfo.ticker == 'US30'
500
else if syminfo.ticker == 'BTCUSDT'
50000
else if syminfo.ticker == 'ETHUSDT'
25000
else if syminfo.type == 'crypto'
500
else if syminfo.type == 'forex'
500
else if syminfo.ticker == 'USOIL'
1000
else
2500
var step = syminfo.mintick * spacing
if barstate.islast
//label.new(bar_index, low, text=syminfo.type, yloc=yloc.abovebar)
for counter = 0 to levels - 1 by 1
price = if syminfo.type == 'index'
math.ceil(close / 4) * 4
else
close
stepUp = math.ceil(price / step) * step + counter * step
stepDown = math.floor(price / step) * step - counter * step
line.new(bar_index, stepUp, bar_index - 1, stepUp, xloc=xloc.bar_index, extend=extend.both, color=lineColor, width=lineWidth, style=line.style_solid)
line.new(bar_index, stepDown, bar_index - 1, stepDown, xloc=xloc.bar_index, extend=extend.both, color=lineColor, width=lineWidth, style=line.style_solid)
label.new(chart.right_visible_bar_time, levels, str.tostring(levels), xloc=xloc.bar_time)
label.new(chart.right_visible_bar_time, levels, str.tostring(levels), xloc=xloc.bar_time)
I tried with different line like, label for exemple
label.new(chart.right_visible_bar_time, levels, str.tostring(levels), xloc=xloc.bar_time)
label.new(chart.right_visible_bar_time, levels, str.tostring(levels), xloc=xloc.bar_time)
That is unfortunately not possible with lines.
If you can draw your lines with the plot() function, you can do it from your chart settings:
Related
I'm actually working on a ruby project and need some help.
I have these inputs :
sizeX and sizeY as an integer
rectangles, which is an array of arrays containing two integers.
I’ll take these values as example :
sizeX = 130
sizeY = 240
rectangles = [ [100,100], [100,150], [50,100], [50,50] ]
With the input i have, i need an algorithm that creates a new rectangle, made of the sizes given in rectangles, that will make a resulting size as closest as sizeX and sizeY. I’m gonna call the created rectangle size rectX and rectY.
This closest determination will be calculated like so :
abs(sizeX - rectX) + abs(sizeY - rectY)
So it returns the smallest total difference
Here are some rules of what the algorithm can and can’t do :
We can use multiple times the same rectangle
We can’t rotate a rectangle (In the case of the example, we can’t have 150x100)
We have to use the least rectangles possible
Here is an illustrated example of a result :
Here is another example if the rectangle [50,100] is not given in rectangles :
I have done some code, but it's not efficient, and is a pretty big mess :
# Returns the biggest cabinet from a given list
def getBiggestCabinet(cabinets)
cabinets.sort_by!{ |rect| rect.cabinetsize_w * rect.cabinetsize_h }.reverse!
return cabinets.first
end
# Returns number of cabinets that fits inside a given width & height + its gap
def getCabinetClosestMatch(width,height,cabinet)
countX = (width / cabinet.cabinetsize_w).floor
countY = (height / cabinet.cabinetsize_h).floor
gapX = width - countX * cabinet.cabinetsize_w
gapY = height - countY * cabinet.cabinetsize_h
return countX, countY, gapX, gapY
end
# Only takes on cabinet at a time
def getBestCabinetByLength(cabinets,gap,match,x_or_y)
sorted = cabinets.sort_by!{ |cabinet|
if x_or_y
return cabinet.cabinetsize_w - gap
else
return cabinet.cabinetsize_h - gap
end
}
bestLength = 0
sorted.each do |cabinet|
if x_or_y
if match.modulo(cabinet.cabinetsize_h) == 0
bestLength = cabinet.cabinetsize_h
break;
end
else
if match.modulo(cabinet.cabinetsize_w) == 0
bestLength = cabinet.cabinetsize_w
break;
end
end
end
return bestLength
end
def createCompatibleArrays(cabinets)
# group cabinets by width or height
cabinets_x = cabinets.group_by{ |c| c.caninetsize_w }.values
cabinets_y = cabinets.group_by{ |c| c.caninetsize_h }.values
return cabinets_x, cabinets_y
end
def getCabinetConfig(cabinets,width,height)
biggestCabinet = getBiggestCabinet(cabinets)
countX, countY, gapX, gapY = getCabinetClosestMatch(width,height,biggestCabinet)
current_width = width - gapX
current_height = height - gapY
cabinets = cabinets.where.not(id: biggestCabinet.id)
cabinets_gx, cabinets_gy = createCompatibleArrays(cabinets)
cabinets_gx.each do |c|
unless c[0].cabinetsize_h / 2 > gapY
end
end
end
whith this strategy i would like to have the open trade in exactly moment of ema crossovers, but all time I have open trade when the next candle open.
It is often a problem because at the ema crossovers I have a bullish push but at the opening of the next candle can be bearish causing the loss of the trade.
Can you help me? thanks
//#version=5
strategy(title='MARCO 18/20', overlay=true)
// STEP 1:
// Make inputs that set the take profit % (optional)
FastPeriod = input.int(title='Fast MA Period', defval=18, group='Moving Average')
SlowPeriod = input.int(title='Slow MA Period', defval=20, group='Moving Average')
TPPerc = input.float(title='Long Take Profit (%)', defval=0.11, group='TP & SL')
SLPerc = input.float(title='Long Stop Loss (%)', defval=4.4, group='TP & SL')
TP_Ratio = input.float(title='Sell Postion Size % # TP', defval=100, group='TP & SL', tooltip='Example: 100 closing 100% of the position once TP is reached') / 100
// Calculate moving averages
fastSMA = ta.sma(close, FastPeriod)
slowSMA = ta.sma(close, SlowPeriod)
// Calculate trading conditions
enterLong = ta.crossover(fastSMA, slowSMA)
// Plot moving averages
plot(series=fastSMA, color=color.new(color.green, 0), title='Fase MA')
plot(series=slowSMA, color=color.new(color.red, 0), title='Slow MA')
// STEP 2:
// Figure out take profit price
percentAsPoints(pcnt) =>
strategy.position_size != 0 ? math.round(pcnt / 100.0 * strategy.position_avg_price / syminfo.mintick) : float(na)
percentAsPrice(pcnt) =>
strategy.position_size != 0 ? (pcnt / 100.0) * strategy.position_avg_price : float(na)
current_position_size = math.abs(strategy.position_size)
initial_position_size = math.abs(ta.valuewhen(strategy.position_size[1] == 0.0, strategy.position_size, 0))
TP = strategy.position_avg_price + percentAsPoints(TPPerc) * syminfo.mintick * strategy.position_size / math.abs(strategy.position_size)
SL = strategy.position_avg_price - percentAsPoints(SLPerc) * syminfo.mintick * strategy.position_size / math.abs(strategy.position_size)
// Submit entry orders
if enterLong
strategy.entry(id='Long', direction=strategy.long)
// STEP 3:
// Submit exit orders based on take profit price
if strategy.position_size > 0
strategy.exit('TP', from_entry='Long', limit=TP, stop=SL)
// Plot take profit values for confirmation
plot(series=strategy.position_size > 0 ? TP : na, color=color.new(color.green, 0), style=plot.style_circles, linewidth=1, title='Take Profit')
plot(series=strategy.position_size > 0 ? SL : na, color=color.new(color.red, 0), style=plot.style_circles, linewidth=1, title='Stop Loss')
Pine script makes the calculations (runs your code) when the bar closed. After that, if your code has an entry, you can enter a trade on the next trade. Since the bar where you run the script is already closed, the trade will be made on the next trade - open price of the next bar. This is basically how real trade will work, since you can't check a trade that already happened and then decide that this trade is good for you or not. You will have to enter on the next trade.
You can override this if you wish.
try enabling in settings: recalculate strategy on each tick
Using Python 3.7 and the colormath module, I had some fun trying to find the complete opposite of one color (ex. The opposite color of black [0, 0, 0] is yellow [255, 255, 0] with a DE of 101.20397657762743) or trying to find the two colors with the most color difference (i.e. "Navy" [0, 0, 110] and "Chartreuse" [143, 255, 0] with a DE of 119.4740815993416, from my potentially inaccurate testing).
Unfortunately, the only way I have found to find the opposite of a given color is just to bruteforce with a little bit of optimization by comparing the given color with (almost) every single sRGB color combo (or, [0, 0, 0] to [255, 255, 255]).
Python 3.7 code:
from colormath.color_objects import sRGBColor as RGBC, LabColor as LabC
from colormath.color_conversions import convert_color as cv_c
from colormath.color_diff import delta_e_cie2000 as de2k
from time import perf_counter as clock
# Example: X11's "Midnight Blue", edit as 'RGBC(r, g, b,...'
reference = RGBC(25, 25, 112, is_upscaled=1)
lab_ref = cv_c(reference, LabC)
# Set max delta
max_delta = 0
# Set estimate calculation's range inverals as factors of 255 (1, 3, 5, 15, 17, 51, 85, 255)
resolution = 17
# Estimate the opposite color
for sample_r in range(0, 256, resolution):
for sample_g in range(0, 256, resolution):
for sample_b in range(0, 256, resolution):
# Convert the sample to Lab
sample = RGBC(sample_r, sample_g, sample_b, is_upscaled=1)
lab_samp = cv_c(sample, LabC)
# Find the color difference
delta = de2k(lab_ref, lab_samp)
# Compare current delta with previous highest delta
if delta > max_delta:
# Overwrite highest delta with current delta
max_delta = delta
# Save estimate for optimization
estimate = sample.get_upscaled_value_tuple()
# Keep any 255 values from estimate, leads to 'range(255, 256)'
low_r = 0 if estimate[0] != 255 else 255
low_g = 0 if estimate[1] != 255 else 255
low_b = 0 if estimate[2] != 255 else 255
# Keep any 0 values from estimate, leads to 'range(0, 1)'
high_r = 256 if estimate[0] != 0 else 1
high_g = 256 if estimate[1] != 0 else 1
high_b = 256 if estimate[2] != 0 else 1
# Reset max delta
max_delta = 0
# Find a better opposite color from estimate
for sample_r in range(low_r, high_r):
for sample_g in range(low_g, high_g):
for sample_b in range(low_b, high_b):
# Convert the sample color to Lab
sample = RGBC(sample_r, sample_g, sample_b, is_upscaled=1)
lab_samp = cv_c(sample, LabC)
# Find the color difference
delta = de2k(lab_ref, lab_samp)
# Compare current delta with previous highest delta
if delta > max_delta:
# Overwrite highest delta with current delta
max_delta = delta
# Overwrite best opposite color with current sample
opposite = sample
# Print the reference, opposite color, and delta E
print(f'{reference.get_upscaled_value_tuple()} with {opposite.get_upscaled_value_tuple()}, {max_delta}')
# Print program time
print(clock())
# Example:
# Returns '(25, 25, 112) with (166, 255, 0), 108.95350620860522
# 2.580066949'
The above code will run for 2.5 seconds to about 19 minutes (assumes second opposite calculation takes 128^3 jumps, returns same value) to about 2 hours 15 minutes (assumes worst possible case is 254^3 jumps, as in no optimization occurs) on my system (3.00 GHz)
CIEDE2000's equations can be seen at this site. Notice the notes at the bottom of the page.
I want to know if there is a more efficient algorithm that can find the complete opposite of a given RGB color. I want to be able to use said algorithm to create a spreadsheet that contains every RGB color and its opposite color before CIEDE202X or CIEDE20XX comes out.
Note: this is my first question on StackOverflow
Edit 1:
Created better estimate optimization. Instead of just keeping 0 or 255 if the estimate had one, I would reduce the limits so that they were only at a maximum of +-32 from the estimate. Runtime reduced to at most 4 seconds on 3.00 GHz.
# Red channel optimization
if estimate[0] == 0 or estimate[0] == 255:
low_r = estimate[0]
high_r = estimate[0] + 1
elif estimate[0] > 32 and estimate[0] < 224:
low_r = estimate[0] - 32
high_r = estimate[0] + 32
elif estimate[0] < 33:
low_r = 0
high_r = estimate[0] + 32
else:
low_r = estimate[0] - 32
high_r = 256
# Green channel optimization
if estimate[1] == 0 or estimate[1] == 255:
low_g = estimate[1]
high_g = estimate[1] + 1
elif estimate[1] > 32 and estimate[1] < 224:
low_g = estimate[1] - 32
high_g = estimate[1] + 32
elif estimate[1] < 33:
low_g = 0
high_g = estimate[1] + 32
else:
low_g = estimate[1] - 32
high_g = 256
# Blue channel optimization
if estimate[2] == 0 or estimate[2] == 255:
low_b = estimate[2]
high_b = estimate[2] + 1
elif estimate[2] > 32 and estimate[2] < 224:
low_b = estimate[2] - 32
high_b = estimate[2] + 32
elif estimate[2] < 33:
low_b = 0
high_b = estimate[2] + 32
else:
low_b = estimate[2] - 32
high_b = 256
CIE DeltaE 2000 is not appropriate for large colour differences so large differences in the range [10, 20]+ simply cannot be evaluated with this quasi-metric and you should probably look at something else such as HyAB colour difference metric: https://onlinelibrary.wiley.com/doi/abs/10.1002/col.22451 or alike.
For some reason when I try to reverse the sign of my current velocity in MATLAB, it just won't do it.
For example, I start off with velocity_x = 3 and velocity_y = 3 (I am drawing circle collisions).
Now inside of checking conditions I need to reverse the sign and I do the following:
% This doesn't work:
velocity_x = -velocity_x;
velocity_y = -velocity_y;
These expressions don't seem to work. Even though in the variable list it still shows as -3, the ball is just twitching and not going in the opposite direction. But when I simply put numbers there, it works fine!
% This works perfectly fine:
velocity_x = -3;
velocity_y = -3;
Here's the whole loop:
velocity_x = 3;
velocity_y = 3;
% While is not commanded to exit the loop
while exit_loop == false
[b1_x_c, b1_y_c] = getCenter(b1);
xMove(b1, velocity_x);
yMove(b1, velocity_y);
if ((b1_x_c + radius + 1) >= WINDOW_WIDTH) || ((b1_y_c + radius + 1) >= WINDOW_HEIGHT)
velocity_x = -1 * velocity_x;
velocity_y = -1 * velocity_y;
elseif ((b1_x_c - radius - 1) <= 0) || ((b1_y_c - radius - 1) <= 0)
velocity_x = (-1) * velocity_x;
velocity_y = (-1) * velocity_y;
end
redraw;
end % of the while loop
When you come in region where if or elseif condition fulfills, sign could change every cycle turn - velocity value 3 -3 3 -3 and so on...
You have to use some flag to indicate that the sign has already been changed and don't change it until that region will be leaved (a kind of hysteresis)
I need to make a chart with an optimized y axis maximum value.
The current method I have of making charts simply uses the maximum value of all the graphs, then divides it by ten, and uses that as grid lines. I didn't write it.
Update Note: These graphs have been changed. As soon as I fixed the code, my dynamic graphs started working, making this question nonsensical (because the examples no longer had any errors in them). I've updated these with static images, but some of the answers refrence different values. Keep that in mind.
There were between 12003 and 14003 inbound calls so far in February. Informative, but ugly.
I'd like to avoid charts that look like a monkey came up with the y-axis numbers.
Using the Google charts API helps a little bit, but it's still not quite what I want.
The numbers are clean, but the top of the y value is always the same as the maximum value on the chart. This chart scales from 0 to 1357. I need to have calculated the proper value of 1400, problematically.
I'm throwing in rbobby's defanition of a 'nice' number here because it explains it so well.
A "nice" number is one that has 3 or fewer non-zero digits (eg. 1230000)
A "nice" number has the same or few non-zero digits than zero digits (eg 1230 is not nice, 1200 is nice)
The nicest numbers are ones with multiples of 3 zeros (eg. "1,000", "1,000,000")
The second nicest numbers are onces with multples of 3 zeros plus 2 zeros (eg. "1,500,000", "1,200")
Solution
I found the way to get the results that I want using a modified version of Mark Ransom's idea.
Fist, Mark Ransom's code determines the optimum spacing between ticks, when given the number of ticks. Sometimes this number ends up being more than twice what the highest value on the chart is, depending on how many grid lines you want.
What I'm doing is I'm running Mark's code with 5, 6, 7, 8, 9, and 10 grid lines (ticks) to find which of those is the lowest. With a value of 23, the height of the chart goes to 25, with a grid line at 5, 10, 15, 20, and 25. With a value of 26, the chart's height is 30, with grid lines at 5, 10, 15, 20, 25, and 30. It has the same spacing between grid lines, but there are more of them.
So here's the steps to just-about copy what Excel does to make charts all fancy.
Temporarily bump up the chart's highest value by about 5% (so that there is always some space between the chart's highest point and the top of the chart area. We want 99.9 to round up to 120)
Find the optimum grid line placement
for 5, 6, 7, 8, 9, and 10 grid
lines.
Pick out the lowest of those numbers. Remember the number of grid lines it took to get that value.
Now you have the optimum chart height. The lines/bar will never butt up against the top of the chart and you have the optimum number of ticks.
PHP:
function roundUp($maxValue){
$optiMax = $maxValue * 2;
for ($i = 5; $i <= 10; $i++){
$tmpMaxValue = bestTick($maxValue,$i);
if (($optiMax > $tmpMaxValue) and ($tmpMaxValue > ($maxValue + $maxValue * 0.05))){
$optiMax = $tmpMaxValue;
$optiTicks = $i;
}
}
return $optiMax;
}
function bestTick($maxValue, $mostTicks){
$minimum = $maxValue / $mostTicks;
$magnitude = pow(10,floor(log($minimum) / log(10)));
$residual = $minimum / $magnitude;
if ($residual > 5){
$tick = 10 * $magnitude;
} elseif ($residual > 2) {
$tick = 5 * $magnitude;
} elseif ($residual > 1){
$tick = 2 * $magnitude;
} else {
$tick = $magnitude;
}
return ($tick * $mostTicks);
}
Python:
import math
def BestTick(largest, mostticks):
minimum = largest / mostticks
magnitude = 10 ** math.floor(math.log(minimum) / math.log(10))
residual = minimum / magnitude
if residual > 5:
tick = 10 * magnitude
elif residual > 2:
tick = 5 * magnitude
elif residual > 1:
tick = 2 * magnitude
else:
tick = magnitude
return tick
value = int(input(""))
optMax = value * 2
for i in range(5,11):
maxValue = BestTick(value,i) * i
print maxValue
if (optMax > maxValue) and (maxValue > value + (value*.05)):
optMax = maxValue
optTicks = i
print "\nTest Value: " + str(value + (value * .05)) + "\n\nChart Height: " + str(optMax) + " Ticks: " + str(optTicks)
This is from a previous similar question:
Algorithm for "nice" grid line intervals on a graph
I've done this with kind of a brute
force method. First, figure out the
maximum number of tick marks you can
fit into the space. Divide the total
range of values by the number of
ticks; this is the minimum
spacing of the tick. Now calculate
the floor of the logarithm base 10 to
get the magnitude of the tick, and
divide by this value. You should end
up with something in the range of 1 to
10. Simply choose the round number greater than or equal to the value and
multiply it by the logarithm
calculated earlier. This is your
final tick spacing.
Example in Python:
import math
def BestTick(largest, mostticks):
minimum = largest / mostticks
magnitude = 10 ** math.floor(math.log(minimum) / math.log(10))
residual = minimum / magnitude
if residual > 5:
tick = 10 * magnitude
elif residual > 2:
tick = 5 * magnitude
elif residual > 1:
tick = 2 * magnitude
else:
tick = magnitude
return tick
You could round up to two significant figures. The following pseudocode should work:
// maxValue is the largest value in your chart
magnitude = floor(log10(maxValue))
base = 10^(magnitude - 1)
chartHeight = ceiling(maxValue / base) * base
For example, if maxValue is 1357, then magnitude is 3 and base is 100. Dividing by 100, rounding up, and multiplying by 100 has the result of rounding up to the next multiple of 100, i.e. rounding up to two significant figures. In this case, the result if 1400 (1357 ⇒ 13.57 ⇒ 14 ⇒ 1400).
In the past I've done this in a brute force-ish sort of way. Here's a chunk of C++ code that works well... but for a hardcoded lower and upper limits (0 and 5000):
int PickYUnits()
{
int MinSize[8] = {20, 20, 20, 20, 20, 20, 20, 20};
int ItemsPerUnit[8] = {5, 10, 20, 25, 50, 100, 250, 500};
int ItemLimits[8] = {20, 50, 100, 250, 500, 1000, 2500, 5000};
int MaxNumUnits = 8;
double PixelsPerY;
int PixelsPerAxis;
int Units;
//
// Figure out the max from the dataset
// - Min is always 0 for a bar chart
//
m_MinY = 0;
m_MaxY = -9999999;
m_TotalY = 0;
for (int j = 0; j < m_DataPoints.GetSize(); j++) {
if (m_DataPoints[j].m_y > m_MaxY) {
m_MaxY = m_DataPoints[j].m_y;
}
m_TotalY += m_DataPoints[j].m_y;
}
//
// Give some space at the top
//
m_MaxY = m_MaxY + 1;
//
// Figure out the size of the range
//
double yRange = (m_MaxY - m_MinY);
//
// Pick the initial size
//
Units = MaxNumUnits;
for (int k = 0; k < MaxNumUnits; k++)
{
if (yRange < ItemLimits[k])
{
Units = k;
break;
}
}
//
// Adjust it upwards based on the space available
//
PixelsPerY = m_rcGraph.Height() / yRange;
PixelsPerAxis = (int)(PixelsPerY * ItemsPerUnit[Units]);
while (PixelsPerAxis < MinSize[Units]){
Units += 1;
PixelsPerAxis = (int)(PixelsPerY * ItemsPerUnit[Units]);
if (Units == 5)
break;
}
return ItemsPerUnit[Units];
}
However something in what you've said tweaked me. To pick nice axis numbers a definition of "nice number" would help:
A "nice" number is one that has 3 or fewer non-zero digits (eg. 1230000)
A "nice" number has the same or few non-zero digits than zero digits (eg 1230 is not nice, 1200 is nice)
The nicest numbers are ones with multiples of 3 zeros (eg. "1,000", "1,000,000")
The second nicest numbers are onces with multples of 3 zeros plus 2 zeros (eg. "1,500,000", "1,200")
Not sure if the above definition is "right" or actually helpful (but with the definition in hand it then becomes a simpler task to devise an algorithm).
A slight refinement and tested... (works for fractions of units and not just integers)
public void testNumbers() {
double test = 0.20000;
double multiple = 1;
int scale = 0;
String[] prefix = new String[]{"", "m", "u", "n"};
while (Math.log10(test) < 0) {
multiple = multiple * 1000;
test = test * 1000;
scale++;
}
double tick;
double minimum = test / 10;
double magnitude = 100000000;
while (minimum <= magnitude){
magnitude = magnitude / 10;
}
double residual = test / (magnitude * 10);
if (residual > 5) {
tick = 10 * magnitude;
} else if (residual > 2) {
tick = 5 * magnitude;
} else if (residual > 1) {
tick = 2 * magnitude;
} else {
tick = magnitude;
}
double curAmt = 0;
int ticks = (int) Math.ceil(test / tick);
for (int ix = 0; ix < ticks; ix++) {
curAmt += tick;
BigDecimal bigDecimal = new BigDecimal(curAmt);
bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println(bigDecimal.stripTrailingZeros().toPlainString() + prefix[scale] + "s");
}
System.out.println("Value = " + test + prefix[scale] + "s");
System.out.println("Tick = " + tick + prefix[scale] + "s");
System.out.println("Ticks = " + ticks);
System.out.println("Scale = " + multiple + " : " + scale);
}
If you want 1400 at the top, how about adjusting the last two parameters to 1400 instead of 1357:
You could use div and mod. For example.
Let's say you want your chart to round up by increments of 20 (just to make it more a more arbitrary number than your typical "10" value).
So I would assume that 1, 11, 18 would all round up to 20. But 21, 33, 38 would round to 40.
To come up with the right value do the following:
Where divisor = your rounding increment.
divisor = 20
multiple = maxValue / divisor; // Do an integer divide here.
if (maxValue modulus divisor > 0)
multiple++;
graphMax = multiple * maxValue;
So now let's plugin real numbers:
divisor = 20;
multiple = 33 / 20; (integer divide)
so multiple = 1
if (33 modulus 20 > 0) (it is.. it equals 13)
multiple++;
so multiple = 2;
graphMax = multiple (2) * maxValue (20);
graphMax = 40;