TradingView Pine Script Multiple crossover strategy - algorithmic-trading

I am desperately looking for help with writing a strategy in trading view where I'm trying to create a crossover buy and sell signals on 3 different MA's , specifically a 9 ema , 21 ema, and 33 simple moving average. What I'm trying to do is have a long condition present itself when the 9 ema crosses above the 21 ema and also having the same long condition happen when the 21 ema crosses above the 33 simple moving average. I want this to work for both Long's and shorts - using the 9 & 21 as a "Small Signal" while using the 21 and 33 as a "Large Signal" and I can't figure it out... this is the closest I have below and it wont work correctly
//#version=3
//study(title="MA Crossover Strategy", overlay = true)
strategy("EMA Crossover Strategy", overlay=true)
src = input(close, title="Source")
price = security(tickerid, period, src)
ema1 = input(9, title="1st EMA Length")
type1 = input("EMA", "1st EMA Type", options=["SMA", "EMA"])
ema2 = input(21, title="2nd EMA Length")
type2 = input("EMA", "2nd EMA Type", options=["SMA", "EMA"])
sma3 = input(33, title="1st MA Length")
type3 = input("SMA", "2nd SMA type", options=["SMA", "EMA"])
price1 = if (type1 == "EMA")
ema(price, ema1)
else
sma(price, ema1)
price2 = if (type2 == "EMA")
sma(price, ema2)
else
ema(price, ema2)
price3 = if (type3 == "SMA")
sma(price, sma3)
else
ema(price, sma3)
//plot(series=price, style=line, title="Price", color=black, linewidth=1, transp=0)
plot(series=price1, style=line, title="1st EMA", color=blue, linewidth=2, transp=0)
plot(series=price2, style=line, title="2nd EMA", color=yellow, linewidth=2, transp=0)
plot(series=price3, style=line, title="1st MA", color=orange, linewidth=2, transp=0)
longCondition = crossover(price1, price2) and crossover(price2, price3)
if (longCondition)
strategy.entry("Long", strategy.long)
shortCondition = crossunder(price1, price2) and crossover(price2, price3)
if (shortCondition)
strategy.entry("Short", strategy.short)
The signals wont show up but If you delete the last "and crossover" part of both conditions it will work only for the 9 ema and 21 ema but I want to incorporate the 21 ema and 33 simple cross.
These are the signals I am trying to replicate for a strategy, the code was used to create the indicator but I'm having a hard time translating it to a strategy. You see the initial signal is given when the 9ema crosses the 21ema and the larger signal is given when the 21ema crosses the 33 simple ma...

Please copy your code with spaces/tabs next time, so it does not require reformatting. Also, do not use [tradingiew-api] tag for Pine-related questions, as is mentioned in the tag's description.
You were using and in your conditions, which entailed that both crosses needed to occur on the same bar for condition to be true. Also inverted your ema/sma calcs for second MA.
Always best to print a marker on your conditions to be sure they occur when you expect them too.
//#version=3
//study(title="MA Crossover Strategy", overlay = true)
strategy("EMA Crossover Strategy", overlay=true)
src = input(close, title="Source")
price = security(tickerid, period, src)
ema1 = input(9, title="1st EMA Length")
type1 = input("EMA", "1st EMA Type", options=["SMA", "EMA"])
ema2 = input(21, title="2nd EMA Length")
type2 = input("EMA", "2nd EMA Type", options=["SMA", "EMA"])
sma3 = input(33, title="3rd MA Length")
type3 = input("SMA", "3rd SMA type", options=["SMA", "EMA"])
price1 = if (type1 == "EMA")
ema(price, ema1)
else
sma(price, ema1)
price2 = if (type2 == "EMA")
ema(price, ema2)
else
sma(price, ema2)
price3 = if (type3 == "SMA")
sma(price, sma3)
else
ema(price, sma3)
//plot(series=price, style=line, title="Price", color=black, linewidth=1, transp=0)
plot(series=price1, style=line, title="1st EMA", color=blue, linewidth=2, transp=0)
plot(series=price2, style=line, title="2nd EMA", color=yellow, linewidth=2, transp=0)
plot(series=price3, style=line, title="1st MA", color=orange, linewidth=2, transp=0)
longCondition = crossover(price1, price2) or crossover(price2, price3)
if (longCondition)
strategy.entry("Long", strategy.long)
shortCondition = crossunder(price1, price2) or crossover(price2, price3)
if (shortCondition)
strategy.entry("Short", strategy.short)
plotchar(shortCondition, "shortCondition", "▼", location.abovebar, maroon, size = size.tiny)
plotchar(longCondition, "longCondition", "▲", location.belowbar, lime, size = size.tiny)

Related

How to draw a horizontal line on high and low of candle visible across at least 2 timeframes?

How to draw a horizontal line on high and low of candle visible across at least 2 timeframes ?
Here is the code written:
i_startTime_27dec22 = input.time(timestamp("27 dec 2022 15:25 +0530"), title = "Start Time")
i_endTime_27dec22 = input.time(timestamp("27 dec 2022 15:30 +0530"), title = "End Time")
inDateRange_27dec22 = time > i_startTime_27dec22 and time < i_endTime_27dec22 and time == not(timeframe.isweekly or timeframe.ismonthly)
l1h = inDateRange_27dec22 ? line.new(bar_index -5, high, bar_index, high, xloc=xloc.bar_index, extend=extend.both, style=line.style_solid, width=1, color=color.blue) : na
l1l = inDateRange_27dec22 ? line.new(bar_index -5, low, bar_index, low, xloc=xloc.bar_index, extend=extend.both, style=line.style_solid, width=1, color=color.blue) : na
2 H-lines are displayed (drawn) on 5 min timeframe. How can I extend the H-lines drawn to be visible across multiple time frames , intraday and daily ? ( Weekly, monthly not required)
i_startTime_27dec22 = input.time(timestamp("27 dec 2022 15:25 +0530"), title = "Start Time")
i_endTime_27dec22 = input.time(timestamp("27 dec 2022 15:30 +0530"), title = "End Time")
inDateRange_27dec22 = time > i_startTime_27dec22 and time < i_endTime_27dec22 and time == not(timeframe.isweekly or timeframe.ismonthly)
l1h = inDateRange_27dec22 ? line.new(bar_index -5, high, bar_index, high, xloc=xloc.bar_index, extend=extend.both, style=line.style_solid, width=1, color=color.blue) : na
l1l = inDateRange_27dec22 ? line.new(bar_index -5, low, bar_index, low, xloc=xloc.bar_index, extend=extend.both, style=line.style_solid, width=1, color=color.blue) : na
How do I extend the logic to include multiple timeframes ?

How to draw a fan in Pine v5? Lines connecting open/close in a range?

Hello I'm new to pine and i have a question.
I would like to write a script that helps me drawing lines connecting the close of the first candle in a selected range and the close of every other candle in the range.
I think I have some problem understanding pine runtime because using for loops or conditional structures seems bad but I can't find a solution around this.
I tried with if but had no succes, the idea was that
after i select the start/end point, the code should be something like this:
if bar_index > bar_index[barStart] and bar_index < bar_index[barEnd]
line.new(bar_index[barStart], close[barStart], bar_index, close)
else na
After this I tried with a for loop, again with no success:
for i = bar_index[barStart]+1 to bar_index[barEnd]
line.new(bar_index[barStart], close[barStart], bar_index[i], close[i])
The code I use to select the range and count the candles inside it is this one:
//#version=5
indicator("Close", overlay=true)
// Range Start
t0 = input.time(timestamp("20 Jul 2021 00:00 +0300"), confirm = true)
p0 = input.price(defval = 0, confirm = true)
// Range End
t1 = input.time(timestamp("20 Jul 2021 00:00 +0300"), confirm = true)
p1 = input.price(defval = 0, confirm = true)
///////////////////////////////////////////////////////////////////////////////////
// Bar counting
t_bar(_t) =>
var int _bar = na
if time_close[1] <= _t and time >= _t
_bar := bar_index
_bar
start = int(t_bar(t0))
end = int(t_bar(t1))
//Counting bars in the selected range
barStart = bar_index - start
barEnd = bar_index - end
barDelta = end - start
//Print results
plot(barStart, "Range start")
plot(barEnd, "Range end")
plot(barDelta, "Candles in range")
But from here on I don't know how to proceed. This should be pretty easy but I'm stuck.
What I'm trying to draw
Thank you to anyone willing to help!!
You don't need the loop or the input price variables. The lines can be drawn bar by bar as the script's execution enters your time range and the price variables can also be obtained at the same time.
//#version=5
indicator("Close", overlay=true)
// Range Start
t0 = input.time(timestamp("20 Jul 2021 00:00 +0300"), confirm = true)
// Range End
t1 = input.time(timestamp("20 Jul 2021 00:00 +0300"), confirm = true)
///////////////////////////////////////////////////////////////////////////////////
first_bar = time >= t0 and time[1] < t0
in_range = time > t0 and time <= t1
post_bar = time > t1 and time[1] <= t1
var float start_close = na
var int start_index = na
if first_bar
start_close := close
start_index := bar_index
if in_range and not first_bar
line.new(x1 = start_index, y1 = start_close, x2 = bar_index, y2 = close)
if post_bar
num_bars = bar_index[1] - start_index
delta = close[1] - start_close
info_text = "Start Bar : " + str.tostring(start_index) + "\nEnd Bar : " + str.tostring(bar_index[1]) + "\nNumber of bars : " + str.tostring(num_bars) + "\nPrice delta : " + str.tostring(delta)
label.new(x = bar_index[1], y = high[1], style = label.style_label_lower_left, size = size.small, text = info_text)
Follow up question :
To draw the lines on a higher timeframe and have them "persist" once you move to a lower timeframe is a bit trickier. You will have to use an input to manually set the higher timeframe as the script has no way to determine the previous timeframe that it was applied to.
When you set t0 and t1 on the higher timeframe, the timestamp values will correspond to the opening time for those higher time frame bars. This isn't ideal as the lower timeframe candle that starts at this same time isn't the close value we are after.
By using request.security() we can then get the actual closing time of the higher timeframe bar which has the closing value we do want.
So we can use time to determine when we've started the correct higher time frame bars and then use time_close to determine when we are on the lower time frame bar that coincides with the higher timeframe close.
//#version=5
indicator("MTF Close", overlay=true)
// Range Start
t0 = input.time(timestamp("20 Jul 2021 00:00 +0300"), confirm = true)
// Range End
t1 = input.time(timestamp("20 Jul 2021 00:00 +0300"), confirm = true)
///////////////////////////////////////////////////////////////////////////////////
tf = input.timeframe("240", title = "higher timeframe")
htf_close = request.security(syminfo.tickerid, tf, time_close)
is_htf_closing_bar = time_close == htf_close
new_htf = ta.change(time(tf)) != 0
var bool started_first_htf_bar = false
var float start_close = na
var int start_index = na
var bool started_last_htf_bar = false
if time >= t0 and time[1] < t0 and new_htf
started_first_htf_bar := true
else if new_htf
started_first_htf_bar := false
if started_first_htf_bar and is_htf_closing_bar and na(start_close)
start_close := close
start_index := bar_index
else if not started_first_htf_bar and is_htf_closing_bar and time > t0 and time < t1
line.new(x1 = start_index, y1 = start_close, x2 = bar_index, y2 = close)
if time >= t1 and time[1] < t1 and new_htf
started_last_htf_bar := true
else if new_htf
started_last_htf_bar := false
if started_last_htf_bar and is_htf_closing_bar
line.new(x1 = start_index, y1 = start_close, x2 = bar_index, y2 = close)
post_bar = new_htf and started_last_htf_bar[1]
if post_bar
num_bars = bar_index[1] - start_index
delta = close[1] - start_close
info_text = "Start Bar : " + str.tostring(start_index) + "\nEnd Bar : " + str.tostring(bar_index[1]) + "\nNumber of bars : " + str.tostring(num_bars) + "\nPrice delta : " + str.tostring(delta)
label.new(x = bar_index[1], y = high[1], style = label.style_label_lower_left, size = size.small, text = info_text)

Only last week value pine script

I am trying to get only last week high/low values,NOT all weeks values
t = input(title = "study", defval="W", options=["D","W"])
shigh = security(tickerid, t, high[1], barmerge.gaps_off, barmerge.lookahead_on)
slow = security(tickerid, t, low[1], barmerge.gaps_off, barmerge.lookahead_on)
r = shigh-slow
center=(sclose)
h1=sclose + r*(1.1/12)
c5=sopen != sopen[1] ? na : red
plot(h5, title="H5",color=c5, linewidth=2)
As you can see in the chart are displayed all weeks since creation...I want only last week!not to show all of them into the chart.
Can someone show me how its done?
//#version=4
study("My Script", overlay=true)
t = input(title = "study", defval="W", options=["D","W"])
[sopen, shigh, slow, sclose] = security(syminfo.tickerid, t, [open[1], high[1],low[1],close[1]], barmerge.gaps_off, barmerge.lookahead_on)
r = shigh-slow
center = (sclose)
h5 = sclose + r*(1.1/12)
c5 = sopen != sopen[1] ? na : color.red
plot(h5, title="H5",color=c5, linewidth=2)
Update: only show current week.
//#version=4
study("My Script", overlay=true)
t = input(title = "study", defval="W", options=["D","W"])
thisweek = year(timenow) == year(time) and weekofyear(timenow) == weekofyear(time)
[sopen, shigh, slow, sclose] = security(syminfo.tickerid, t, [open[1], high[1],low[1],close[1]], barmerge.gaps_off, barmerge.lookahead_on)
r = shigh-slow
center = (sclose)
h5 = sclose + r*(1.1/12)
c5 = sopen != sopen[1] ? na : color.red
plot(thisweek ? h5 : na, title="H5",color=c5, linewidth=2)

Mathematical solution to split X teams into 3 Teams per day

I am trying to split X number of Teams into "play days" which consist of 3 teams per day
There is more than one solution to solve this for 15 teams.
What is the best approach to find all possible fixtures/match plans for team count 9-21?
Team count of 11, 14, 17 and 20 also cause problems, because total_matches/3="must be even/integer"
15 Teams // 105 Total Matches // 35 Total Days
D1 = 1:2 1:3 2:3
D2 = 2:4 2:5 4:5
D3 = 3:4 3:6 4:6
D4 = 4:1 4:7 1:7
D5 = 5:1 5:6 1:6
D6 = 6:2 6:7 2:7
7 = 7:3 7:5 3:5
8 = 8:1 8:9 1:9
9 = 9:2 9:10 2:10
10 = 10:1 10:11 1:11
11 = 11:2 11:8 2:8
12 = 12:1 12:13 1:13
13 = 13:2 13:14 2:14
14 = 14:1 14:15 1:15
15 = 2:12 2:15 12:15
16 = 3:8 3:10 8:10
17 = 3:9 3:11 9:11
18 = 3:12 3:14 12:14
19 = 4:8 4:12 8:12
20 = 5:8 5:13 8:13
21 = 6:8 6:14 8:14
22 = 7:8 7:15 8:15
23 = 9:4 9:13 4:13
24 = 9:5 9:12 5:12
25 = 10:4 10:14 4:14
26 = 11:4 11:15 4:15
27 = 12:6 12:10 6:10
28 = 13:3 13:15 3:15
29 = 14:5 14:11 5:11
30 = 5:10 5:15 10:15
D31 = 6:9 6:15 9:15
D32 = 6:11 6:13 11:13
D33 = 7:9 7:14 9:14
D34 = 7:10 7:13 10:13
D35 = 7:11 7:12 11:12
(Python) The following chooses the next three teams to group per day based on those teams that have played the least games so far and gives an ideal solution for the 9 teams case:
from itertools import combinations
from string import ascii_uppercase
TEAMCOUNT = 9
teams = ascii_uppercase[:TEAMCOUNT] # Just use uppercase letters for teams
# All needed 2-team games
games = {''.join(two_teams) for two_teams in combinations(teams, 2)}
# All possible 3-team days and the 2-team matches they map to
triples = {x + y + z: {x+y, x+z, y+z}
for x, y, z in combinations(teams, 3) }
print('Teams:', teams)
n = 0
while games and triples:
# Weighting based on number of games left to play
weight = {t: sum(t in g for g in games) for t in teams}
to_play = {t1+t2: min([weight[t1], weight[t2]]) for t1, t2 in games}
# Choose teams that haven't played much next
_, chosen_triple = max((sum(to_play[m] for m in matches if m in games),
day)
for day, matches in triples.items())
n += 1
print(f" Day{n}: {chosen_triple} Games: ",
' '.join(sorted(m for m in triples[chosen_triple] if m in games)))
games -= triples[chosen_triple] # These games are played
del triples[chosen_triple] # This day triple used
if games:
print(" After those days, the following games remain to be played:", ' '.join(sorted(games)))
else:
print(" All games played!")
Output for 9 Teams:
Teams: ABCDEFGHI
Day1: GHI Games: GH GI HI
Day2: DEF Games: DE DF EF
Day3: ABC Games: AB AC BC
Day4: CFI Games: CF CI FI
Day5: BEH Games: BE BH EH
Day6: ADG Games: AD AG DG
Day7: CEG Games: CE CG EG
Day8: BDI Games: BD BI DI
Day9: AFH Games: AF AH FH
Day10: CDH Games: CD CH DH
Day11: BFG Games: BF BG FG
Day12: AEI Games: AE AI EI
All games played!
The number of possible combinations/matches of teams can mathematically be described as a Triangular Number.
For example, when there is 9 teams, the number of matches is 36.
Notice, that this number is only divisible by 3 when k or k-1 is divisible by 3. With 5 teams, you will end up with 10 possible games. Your last week will only have 1 game or you can structure it differently.
If you want to write out the combinations of matches, you can list them by iterating through the number of teams twice. Here is some example Java code. You may run it in an online Java compiler.
public class MyClass {
public static void main(String args[]) {
int TEAMS = 10; //Number of teams
int combos = 0;
for(int i = 1; i <= TEAMS-1; i++){
for(int j = i+1; j <= TEAMS; j++){
System.out.println("Team " + i + " plays Team " + j);
combos ++;
}
}
System.out.println("There is " + combos + " possible matches");
}
}
We don't just want every combination of 2 teams. We want to look at combinations of 3 teams. Mathematically, we want a Combination.
We can rewrite our Triangular number as n choose k. Our previous example becomes:
Every week that we choose has 3 teams playing. The total possible day combinations is n choose 3. In our example with 9 teams.
We have 84 possible day combinations. Many of these days have overlapping games. For example, if we have teams 1, 2, and 3 play one day, then we don't want another day with teams 1,2 and 4 because then 1 and 2 play 2 games against each other. The solution for this could be to ignore duplicated games.
I want to point out that a perfect solution does not exist. For most number of teams, there is not a solution where every day 3 teams can play together that haven't already played. For example, when we have 4 teams, our games are:
1-2, 1-3, 1-4, 2-3, 2-4, 3-4. If we took 3 of those teams the first day (1-2, 1-3, 2-3) then the second day we don't get a perfect combination (1-4, 2-4, 3-4).
No matter how you break it, you can sort for the best combinations but you will end up with many random games at the end.
I created code below to look at every possible day combination and print out days that are not duplicated.
public class MyClass {
public static void main(String args[]) {
int TEAMS = 9; //Number of teams
//Keep track of each game combination used
boolean gamesPlayed[][] = new boolean[TEAMS+1][TEAMS+1];
int day = 1;
for(int i = 1; i <= TEAMS-2; i++){
for(int j = i+1; j <= TEAMS-1; j++){
for(int k = TEAMS; k >= j+1; k--){
if(!gamesPlayed[i][j] && !gamesPlayed[i][k] && !gamesPlayed[j][k] )
{
System.out.println("Day "+ day++ + " Teams " + i + ", " + j + " & " + k + " Play");
gamesPlayed[i][j] = true;
gamesPlayed[i][k] = true;
gamesPlayed[j][k] = true;
}
}
}
}
System.out.println("\nLeftover games");
for(int i = 1; i <= TEAMS-1; i++){
for(int j = i+1; j <= TEAMS; j++){
if(! gamesPlayed[i][j])
System.out.println(" Team " + i + " plays Team " + j);
}
}
}
}

Do I implement this algorithm correctly?

I'm trying to implement the a block conjugate gradient algorithm that is not subject to breakdown from non invertible residual matrices; But I'm getting nonsensical results (in each iteration, the rank of Rcurrent should be getting smaller, not increasing). It is presented in the paper "A breakdown-free block conjugate gradient method" by Hao Ji and Yaohang Li.
Here is the algorithm:
This is my implementation in Julia:
function orth(M::Matrix)
matrixRank = rank(M)
Ufactor = svdfact(M)[:U]
return Ufactor[:,1:matrixRank]
end
function BFBCG(A::Matrix, Xcurrent::Matrix, M::Matrix, tol::Number, maxit::Number, Rcurrent::Matrix)
# initialization
#Rcurrent = B - A*Xcurrent;
Zcurrent = M*Rcurrent;
Pcurrent = orth(Zcurrent);
Xnext::Matrix = ones(size(Xcurrent))
# iterative method
for i = 0:maxit
Qcurrent = A*Pcurrent
acurrent = (Pcurrent' * Qcurrent)\(Pcurrent'*Rcurrent)
Xnext = Xcurrent+Pcurrent*acurrent
Rnext = Rcurrent-Qcurrent*acurrent
# if Residual norm of columns in Rcurrent < tol, stop
Znext = M*Rnext
bcurrent = -(Pcurrent' * Qcurrent)\ (Qcurrent'*Znext)
Pnext = orth(Znext+Pcurrent*bcurrent)
Xcurrent = Xnext
Zcurrent = Znext
Rcurrent = Rnext
Pcurrent = Pnext
#printf("\nRANK:\t%d",rank(Rcurrent))
#printf("\nNORM column1:\t%1.8f",vecnorm(Rcurrent[:,1]))
#printf("\nNORM column2:\t%1.8f\n=============",vecnorm(Rcurrent[:,2]))
end
return Xnext
end
The results of the paper for those inputs:
A = [15 5 4 3 2 1; 5 35 9 8 7 6; 4 9 46 12 11 10; 3 8 12 50 14 13; 2 7 11 14 19 15; 1 6 10 13 15 45]
M = eye(6)
guess = rand(6,2)
R0 = [1 0.537266261211281;2 0.043775211060964;3 0.964458562037146;4 0.622317517840541;5 0.552735938776748;6 0.023323943544997]
X = BFBCG(A,guess,M,tol,9,R0)
are a rank that reaches zero in the third iteration.
The algorithm works, and the rank goes to zero in the third iteration. The problem is numerical inaccuracies which would leave any matrix fully ranked. To get a better result, use rank(Rcurrent, tol) instead of rank(Rcurrent) which is a version which takes tolerance into account. After which, at least on my machine, the rank drops to zero.
julia> X = BFBCG(A,guess,M,tol,9,R0)
RANK: 2
NORM column1: 1.78951939
NORM column2: 0.41155080
=============
RANK: 2
NORM column1: 0.97949620
NORM column2: 0.16170799
=============
RANK: 0
NORM column1: 0.00000000
NORM column2: 0.00000000
=============
RANK: 0
NORM column1: 0.00000000
NORM column2: 0.00000000
=============

Resources