Unexplained Pinescript error shows when trying to parametrize a variable - syntax-error

This is the working version of the script:
//#version=5
indicator("compare MA", overlay= true)
var finallength = 0
Length1MA = input.int(defval = 10, title= "1 MA length")
Length2MA = input.int(defval = 20, title= "2 MA length")
sma1 = ta.sma(close, Length1MA)
sma2 = ta.sma(close, Length2MA)
var count1 = 0.0
var count2 = 0.0
for i = 1 to 10
if not na(sma1[i]) and not na(sma2[i])
count1 := count1 + math.abs(close[i] - sma1[i])
count2 := count2 + math.abs(close[i] - sma2[i])
if count1 > count2
finallength := Length1MA
else
finallength := Length2MA
plot(ta.sma(close, finallength), color= color.red, linewidth=2)
This is a different version that tries to parametrize the amount of Moving Averages, however there is an error i've been stuck to for a long time:
//#version=5
indicator("compare MA", overlay= true)
var finallength = 0
LengthsMA = input(defval=[10,20,30,40], title="MA lengths", type=input.integer)
counts = 0.0
for i = 1 to bar_index
for j = 0 to len(LengthsMA)-1
sma = ta.sma(close, LengthsMA[j])
if not na(sma[i])
counts[j] := counts[j] + math.abs(close[i] - sma[i])
finallength := LengthsMA[highest(counts)]
plot(ta.sma(close, finallength), color= color.red, linewidth=2)
you can run it to see the error first hand at line 12:
counts[j] = counts[j] + math.abs(close[i] - sma[i]) -> gives error -> Syntax error at input '=' (Error at 12:23)
changing it to := will not fix it! the goal is to use many Moving Averages and iterate through them all to find which is furthest from the price for the most time.
The goal is to use as many Moving Averages as needed without writing lines individually and cluttering the code with 20 else if statements, and iterate through them all to find which is furthest from the price.
the problem is this unexplainable error:
Syntax error at input '=' (Error at 12:23)

Unlike some other languages, [] in pinescript is not used for arrays. It is called history reference operator [] and is used to access historical data.
Obviously, you cannot re-write the history :)
So, doing something like
counts[j] := counts[j] + math.abs(close[i] - sma[i])
is not allowed.
If you want to work with arrays, you should use arrays.

Related

Pinescript conditional line end/delete

I’m trying to create lines that auto plot at certain intervals using the line.new() function. So for example every new monthly open there will be lines plotted 5% and 10% above and beneath price. They’re then extended to the right indefinitely.
I then want to have the lines end once high/low has breached the line. I can’t seem to figure how to do this using the line.delete() function, although I doubt this is the correct path to take anyway due to the fact this deletes the entire line rather than just end it at breach point.
Due to the fact lines are extended indefinitely/until price has breached, there may be instances in which lines are never touched and are only removed once the 500 max line limit is reached. So I haven’t figured a way to use array references for lines to find a solution - and the 40 plot limit for pine plots isn’t really a sufficient amount of lines.
If this isn’t possible then just deleting the entire line upon breach is a backup option but I haven’t figure how to do this either!
Any help is much appreciated, thanks in advance!
You can use additional arrays to track the price values and their crossed state more easily. Each element of the arrays corresponds to the values associated with the same line. We add, remove or modify them based on whether a particular line's price value has been crossed or the line limit has been exceeded.
//#version=5
indicator("Monthly Interval Lines", overlay = true, max_lines_count = 500)
var float[] interval_prices = array.new_float()
var line[] interval_lines = array.new_line()
var bool[] intervals_crossed = array.new_bool()
new_month = timeframe.change("M")
if new_month
array.unshift(interval_lines, line.new(x1 = bar_index, y1 = open * 1.05, x2 = bar_index + 1, y2 = open * 1.05, extend = extend.right, color = color.green))
array.unshift(interval_prices, open * 1.05)
array.unshift(intervals_crossed, false)
array.unshift(interval_lines, line.new(x1 = bar_index, y1 = open * 1.10, x2 = bar_index + 1, y2 = open * 1.10, extend = extend.right, color = color.green))
array.unshift(interval_prices, open * 1.10)
array.unshift(intervals_crossed, false)
array.unshift(interval_lines, line.new(x1 = bar_index, y1 = open * 0.95, x2 = bar_index + 1, y2 = open * 0.95, extend = extend.right, color = color.red))
array.unshift(interval_prices, open * 0.95)
array.unshift(intervals_crossed, false)
array.unshift(interval_lines, line.new(x1 = bar_index, y1 = open * 0.90, x2 = bar_index + 1, y2 = open * 0.90, extend = extend.right, color = color.red))
array.unshift(interval_prices, open * 0.90)
array.unshift(intervals_crossed, false)
size = array.size(intervals_crossed)
if size > 0
if size > 500
for i = size - 1 to 500
line.delete(array.pop(interval_lines))
array.pop(intervals_crossed)
size := array.size(intervals_crossed)
for i = 0 to size - 1
price_val = array.get(interval_prices, i)
already_crossed = array.get(intervals_crossed, i)
crossed_price_val = low < price_val and high > price_val
gapped_price_val = (close[1] < price_val and open > price_val) or (close[1] > price_val and open < price_val)
if not already_crossed and (crossed_price_val or gapped_price_val)
array.set(intervals_crossed, i, true)
interval_line = array.get(interval_lines, i)
line.set_extend(interval_line, extend.none)
line.set_x2(interval_line, bar_index)

No method matching error when working with Vector{Int64]

I have the following code where firstly I add the values for each index from two columns and creating Vector{Int64}
df = CSV.read(joinpath("data", "data.csv"), DataFrame)
adding_columns = df.firstcolumn + df.secondcolumn
Then I will create a function as following:
function fnct(data::Vector{T}; var= 8) where { T <: Number }
V = []
for x in 1:size(data)[1]
strt = x-var
ending = x+var
avg = 0
if strt < 1
for y in 1:x+var
avg = avg+data[y]
end
avg = avg/(x+var-1)
elseif ending > size(data)[1]
for y in x-var:size(data)[1]
avg = avg+data[y]
end
avg = avg/(size(data)-x-var)
else
for y in x-var:x+var
avg = avg+data[y]
end
avg = avg/(2*var)
end
push!(V,avg)
end
return V
end
When trying:
typeof(adding_columns)
I will get:
Vector{Int64}
however when calling
fnct(adding_columns)
I will get:
ERROR: MethodError: no method matching -(::Tuple{Int64}, ::Int64)
I presume that it takes my adding_columns as Tuple but I do not get it why, when the typeof is giving me Vector.
How could I solve this problem?
size(data) is a tuple:
julia> size([1,2,3]::Vector{Int})
(3,)
...but you're subtracting an integer from it in avg = avg/(size(data)-x-var).
Did you mean avg = avg/(length(data)-x-var) or avg = avg/(size(data, 1)-x-var)?

Program freezes with specific numbers

This code is supposed to take a number and find it's prime factors.
Why does this code work with numbers like 2345 (which returns 5, 7, 67 like its supposed to) but it doesn't work with numbers like 500 and 800?
EDIT: when I say it doesn't work, the program simply does nothing and/or freezes on button click. I then have to stop the program in vb.
Dim number As Double = txtNum.Text
Dim var As Double = 2
Dim result As Double
If number > 1 Then
lst1.Items.Clear()
lst1.Items.Add("The prime factors of " & number & ":")
Do While number > 1
result = number / var
If result = Int(result) Then
lst1.Items.Add(var)
number = result
End If
var = var + 1
Loop
Else
lst1.Items.Clear()
lst1.Items.Add("Let try that again...")
End If
The problem was caused because 500 divided by 2 is 250, divided by 5 is 50 ... and then the program continued on by dividing by 6 instead of attempting to divide by 5 again. Once var reached 10, number became 5 and no further divisions ever allowed it to reach 1 - thus an infinite loop was created.
By changing
If result = Int(result) Then
lst1.Items.Add(var)
number = result
End If
var = var + 1
to
If result = Int(result) Then
lst1.Items.Add(var)
number = result
Else
var = var + 1
End If
it correctly made multiple divisions by the same prime factor when necessary.

How to Plot a function of two variables in Julia with pyplot

I'm trying to plot a function of two variables with pyplot in Julia. The working starting-point is the following (found here at StackOverflow):
function f(z,t)
return z*t
end
z = linspace(0,5,11)
t = linspace(0,40,4)
for tval in t
plot(z, f(z, tval))
end
show()
This works right for me and is giving me exactly what I wanted:
a field of lines.
My own functions are as follows:
## needed functions ##
const gamma_0 = 6
const Ksch = 1.2
const Kver = 1.5
function Kvc(vc)
if vc <= 0
return 0
elseif vc < 20
return (100/vc)^0.1
elseif vc < 100
return 2.023/(vc^0.153)
elseif vc == 100
return 1
elseif vc > 100
return 1.380/(vc^0.07)
else
return 0
end
end
function Kgamma(gamma_t)
return 1-((gamma_t-gamma_0)/100)
end
function K(gamma_t, vc)
return Kvc(vc)*Kgamma(gamma_t)*Ksch*Kver
end
I've tried to plot them as follows:
i = linspace(0,45,10)
j = linspace(0,200,10)
for i_val in i
plot(i,K(i,j))
end
This gives me the following Error:
isless has no method matching isless(::Int64, ::Array{Float64,1})
while loading In[51], in expression starting on line 3
in Kvc at In[17]:2 in anonymous at no file:4
Obviously, my function cant deal with an array.
Next try:
i = linspace(0,200,11)
j = linspace(0,45,11)
for i_val in i
plot(i_val,map(K,i_val,j))
end
gives me a empty plot only with axes
Can anybody please give me a hint...
EDIT
A simpler example:
using PyPlot
function P(n,M)
return (M*n^3)/9550
end
M = linspace(1,5,5)
n = linspace(0,3000,3001)
for M_val in M
plot(n,P(n,M_val))
end
show()
Solution
OK, with your help I found this solution for the shortened example which works for me as intended:
function P(n,M)
result = Array(Float64, length(n))
for (idx, val) in enumerate(n)
result[idx] = (M*val^3)/9550
end
return result
end
n = linspace(0,3000,3001)
for M_val = 1:5
plot(n,P(n,M_val))
end
show()
This gives me what I wanted for this shortened example. The remainig question is: could it be done in a simpler more elegant way?
I'll try to apply it to the original example and post it when I'll succed.
I don't completely follow all the details of what you're trying to accomplish, but here are examples on how you can modify a couple of your functions so that they accept and return arrays:
function Kvc(vc)
result = Array(Float64, length(vc))
for (idx, val) in enumerate(vc)
if val <= 0
result[idx] = 0
elseif val < 20
result[idx] = (100/val)^0.1
elseif val < 100
result[idx] = 2.023/(val^0.153)
elseif val == 100
result[idx] = 1
elseif val > 100
result[idx] = 1.380/(val^0.07)
else
result[idx] = 0
end
end
return result
end
function Kgamma(gamma_t)
return ones(length(gamma_t))-((gamma_t - gamma_0)/100)
end
Also, for your loop, I think you probably want something like:
for i_val in i
plot(i_val,K(i_val,j))
end
rather than plot(i, K(i,j), as that would just print the same thing over and over.
< is defined for scalars. I think you need to broadcast it for arrays, i.e. use .<. Example:
julia> x = 2
2
julia> x < 3
true
julia> x < [3 4]
ERROR: MethodError: no method matching isless(::Int64, ::Array{Int64,2})
Closest candidates are:
isless(::Real, ::AbstractFloat)
isless(::Real, ::Real)
isless(::Integer, ::Char)
in <(::Int64, ::Array{Int64,2}) at .\operators.jl:54
in eval(::Module, ::Any) at .\boot.jl:234
in macro expansion at .\REPL.jl:92 [inlined]
in (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at .\event.jl:46
julia> x .< [3 4]
1x2 BitArray{2}:
true true

Which points are co-linear & in sequence (i.e. which two points I am between)

I have longitude and latitude of my position, and I have a list of positions that is ordered as a list of points(long/lat)) along a road. How do I find out which two points I am between?
If I just search for the two nearest points I will end up with P2 and P3 in my case in the picture.
I want to know how to find out that I'm between point p1 and p2.
The list of points I will search will be database rows containing latitude and longitude so pointers to how to build the sql-query, linq-query or pseudo code, everything that points me to the best solution is welcome. I'm new to geolocation and the math around it so treat me as an newbie. ;)
(The list of points will be ordered so P1 will have an id of 1, p2 will have an id of 2 and so on. )
Bear in mind that what you propose might become really complex (many points under equivalent conditions) and thus delivering an accurate algorithm would require (much) more work. Taking care of simpler situations (like the one in your picture) is not so difficult; you have to include the following:
Convert latitude/longitude values into cartesian coordinates (for ease of calculations; although you might even skip this step). In this link you can get some inspiration on this front; it is in C#, but the ideas are clear anyway.
Iterate through all the available points "by couples" and check whether the point to be analysed (Mypos), falls in the line formed by them, in an intermediate position. As shown in the code below, this calculation is pretty simple and thus you don't need to do any pre-filtering (looking for closer points before).
.
Dim point1() As Double = New Double() {0, 0} 'x,y
Dim point2() As Double = New Double() {0, 3}
Dim pointToCheck() As Double = New Double() {0.05, 2}
Dim similarityRatio As Double = 0.9
Dim minValSimilarDistance As Double = 0.001
Dim similarityDistance As Double = 0.5
Dim eq1 As Double = (point2(0) - point1(0)) * (pointToCheck(1) - point1(1))
Dim eq2 As Double = (point2(1) - point1(1)) * (pointToCheck(0) - point1(0))
Dim maxVal As Double = eq1
If (eq2 > eq1) Then maxVal = eq2
Dim inLine = False
Dim isInBetween As Boolean = False
If (eq1 = eq2 OrElse (maxVal > 0 AndAlso Math.Abs(eq1 - eq2) / maxVal <= (1 - similarityRatio))) Then
inLine = True
ElseIf (eq1 <= minValSimilarDistance AndAlso eq2 <= similarityDistance) Then
inLine = True
ElseIf (eq2 <= minValSimilarDistance AndAlso eq1 <= similarityDistance) Then
inLine = True
End If
If (inLine) Then
'pointToCheck part of the line formed by point1 and point2, but not necessarily between them
Dim insideX As Boolean = False
If (pointToCheck(0) >= point1(0) AndAlso pointToCheck(0) <= point2(0)) Then
insideX = True
Else If (pointToCheck(0) >= point2(0) AndAlso pointToCheck(0) <= point1(0)) Then
insideX = True
End If
if(insideX) Then
If (pointToCheck(1) >= point1(1) AndAlso pointToCheck(1) <= point2(1)) Then
isInBetween = True
ElseIf (pointToCheck(1) >= point2(1) AndAlso pointToCheck(1) <= point1(1)) Then
isInBetween = True
End If
End If
End If
If (isInBetween) Then
'pointToCheck is between point1 and point2
End If
As you can see, I have included various ratios allowing you to tweak the exact conditions (the points will, most likely, not be falling exactly in the line). similarityRatio accounts for "equations" being more or less similar (that is, X and Y values not exactly fitting within the line but close enough). similarityRatio cannot deal properly with cases involving zeroes (e.g., same X or Y), this is what minValSimilarDistance and similarityDistance are for. You can tune these values or just re-define the ratios (with respect to X/Y variations between points, instead of with respect to the "equations").
An equivalent solution in Scala for clarity:
def colinearAndInOrder(a: Point, b: Point, c: Point) = {
lazy val colinear: Boolean =
math.abs((a.lng - b.lng) * (a.lat - c.lat) -
(a.lng - c.lng) * (a.lat - b.lat)) <= 1e-9
lazy val bounded: Boolean =
((a.lat < b.lat && b.lat < c.lat) || (a.lat > b.lat && b.lat > c.lat)) &&
((a.lng < b.lng && b.lng < c.lng) || (a.lng > b.lng && b.lng > c.lng))
close(a,b) || close(b,c) || (colinear && bounded)
}
def close(a: Point, b: Point): Boolean = {
math.abs(a.lat - b.lng) <= 1e-4 && math.abs(a.lat - b.lng) <= 1e-4
}