How do I add a pre determined stop loss and take profit? - algorithmic-trading

This is my first post. I am a prop trader and really trying hard to learn how to code as it would take my trading to another level. It is quite overwhelming at the beginning, but working on things that have use to me is motivating.
I have a script for trading view that I would like to edit. I have tried myself but I am obviously doing something wrong. Any help would be very much appreciated.
I just want to add my own pre determined stop loss and take profit for the strategy, The code is below:
strategy(title="Z-Score Strategy", shorttitle="Z-Score Strategy")
Period = input(20, minval=1)
Trigger = input(0)
reverse = input(false, title="Trade reverse")
hline(Trigger, color=purple, linestyle=line)
xStdDev = stdev(close, Period)
xMA = sma(close, Period)
nRes = (close - xMA) / xStdDev
pos = iff(nRes > Trigger, 1,
iff(nRes < Trigger, -1, nz(pos[1], 0)))
possig = iff(reverse and pos == 1, -1,
iff(reverse and pos == -1, 1, pos))
if (possig == 1)
strategy.entry("Long", strategy.long)
if (possig == -1)
strategy.entry("Short", strategy.short)
barcolor(possig == -1 ? red: possig == 1 ? green : blue )
plot(nRes, color=blue, title="Z-Score")

You should close the position via strategy.exit: https://www.tradingview.com/pine-script-reference/v4/#fun_strategy{dot}exit
//#version=4
strategy("strategy")
strategy.entry("entryId", strategy.long)
strategy.exit("exitId", "entryId", profit = 5, stop=7)

Related

Pine script strategy open at second open candel and no when EMA crossover

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

Tradingview Pine-Script: How to plot only the last x periods

I'd like to plot an indicator only for the last x periods.
How do I do that?
If I could do time operations (substract x * period from plotStartDate), maybe I could use this code:
period = timeframe.ismonthly or timeframe.isweekly ? "12M" : "M"
plotStartDate = timestamp(year(timenow), month(timenow), dayofmonth(timenow), 00, 00)
isPlotDate = time >= plotStartDate
plot(isPlotDate ? mydata : na, color=mydata != mydata[1]:na, style=plot.style_line, linewidth=2)
Version 1
Not sure this is what you're looking for. It uses plot()'s show_last= parameter to restrict the number of last bars plotted after your isPlotDate constraint has been satisfied:
//#version=4
study("", "", true)
xPeriods = input(10)
plotStartDate = timestamp(year(timenow), month(timenow), dayofmonth(timenow), 00, 00)
isPlotDate = time >= plotStartDate
plot(isPlotDate ? close : na, show_last = xPeriods)
Version 2
//#version=4
study("Plot starting n months back", "", true)
monthsBack = input(3, minval = 0)
monthsExtra = monthsBack % 12
monthsExcedent = month(timenow) - monthsExtra
yearsBack = floor(monthsBack / 12) + (monthsExcedent <= 0 ? 1 : 0)
targetMonth = monthsExcedent <= 0 ? 12 + monthsExcedent : monthsExcedent
targetYearMonth = year == year(timenow) - yearsBack and month == targetMonth
beginMonth = not targetYearMonth[1] and targetYearMonth
var float valueToPlot = na
if beginMonth
valueToPlot := high
plot(valueToPlot)
bgcolor(beginMonth ? color.green : na)
Version 3
Simpler:
//#version=4
study("Plot starting n months back", "", true)
monthsBack = input(3, minval = 0)
targetDate = time >= timestamp(year(timenow), month(timenow) - monthsBack, 1, 0, 0, 0)
beginMonth = not targetDate[1] and targetDate
var float valueToPlot = na
if beginMonth
valueToPlot := high
plot(valueToPlot)
bgcolor(beginMonth ? color.green : na)
Version 4
At v4 you can set the variable show_last in the plot() function.
In "PineScript language reference manual" says:
show_last (input integer) If set, defines the number of bars (from the
last bar back to the past) to plot on chart.
https://www.tradingview.com/pine-script-reference/#fun_plot

Edge case for finding strictly increasing squares of a number

I'm trying to solve this codewars kata, Square into Squares.
I'm passing most of the tests, but there are two inputs for which my algorithm exceeds the maximum call stack size.
I feel like I'm taking care of all the edge conditions, and I can't figure out what I'm missing.
function sumSquares (n) {
function decompose (num, whatsLeft, result) {
if (whatsLeft === 0) return result
else {
if (whatsLeft < 0 || num === 0) return null
else {
return decompose(num-1, whatsLeft - num * num, [num].concat(result)) || decompose(num-1, whatsLeft, result)
}
}
}
return decompose(n-1, n*n, [])
}
const resA = sumSquares(50) //[1,3,5,8,49]
console.log(resA)
const resB = sumSquares(7) //[2,3,6]
console.log(resB)
const resC = sumSquares(11) //[ 1, 2, 4, 10 ]
console.log(resC)
const res1 = sumSquares(90273)
console.log(res1)
const res2 = sumSquares(123456)
console.log(res2)
It looks like your code is correct, but has two problems: first, your call stack will eventually reach size "num" (which may be causing your failure for large inputs), and second, it may recompute the same values multiple times.
The first problem is easy to fix: you can skip num values which give a negative whatsLeft result. Like this:
while(num * num > whatsLeft) num = num - 1;
You can insert this after the first if statement. This also enables you to remove the check for negative whatsLeft. As a matter of style, I removed the else{} cases for your if statements after a return -- this reduces the indentation and (I think) makes the code easier to read. But that's just a matter of personal taste.
function sumSquares (n) {
function decompose (num, whatsLeft, result) {
if (whatsLeft === 0) return result;
while (num * num > whatsLeft) num -= 1;
if (num === 0) return null;
return decompose(num-1, whatsLeft - num * num, [num].concat(result)) || decompose(num-1, whatsLeft, result);
}
return decompose(n-1, n*n, []);
}
Your test cases run instantly for me with these changes, so the second problem (which would be solved by memoization) isn't necessary to address. I also tried submitting it on the codewars site, and with a little tweaking (the outer function needs to be called decompose, so both the outer and inner functions need renaming), all 113 test cases pass in 859ms.
#PaulHankin's answer offers good insight
Let's look at sumSquares (n) where n = 100000
decompose (1e5 - 1, 1e5 * 1e5, ...)
In the first frame,
num = 99999
whatsLeft = 10000000000
Which spawns
decompose (99999 - 1, 1e10 - 99999 * 99999, ...)
Where the second frame is
num = 99998
whatsLeft = 199999
And here's the problem: num * num above is significantly larger than whatsLeft and each time we recur to try a new num that first, we only decrease by -1 each frame. Without fixing anything, the next process spawned will be
decompose (99998 - 1, 199999 - 99998 * 99998, ...)
Where the third frame is
num = 99997
whatsLeft = -9999500005
See how whatsLeft is significantly negative? It means we'll have to decrease num by a lot before the next value doesn't cause whatsLeft to drop below zero
// [frame #4]
num = 99996
whatsLeft = -9999000017
// [frame #5]
num = 99995
whatsLeft = -9998800026
...
// [frame #99552]
num = 448
whatsLeft = -705
// [frame #99553]
num = 447
whatsLeft = 190
As we can see above, it would take almost 100000 frames just to guess the second digit of sumSquares (100000). This is exactly what Paul Hankin describes as your first problem.
We can also visualize it a little easer if we only look at decompose with num. Below, if a solution cannot be found, the stack will grow to size num and therefore cannot be used to compute solutions where num exceeds the stack limit
// imagine num = 100000
function decompose (num, ...) {
...
decompose (num - 1 ...) || decompose (num - 1, ...)
}
Paul's solution uses a while loop to decrement num using a loop until num is small enough. Another solution would involve calculating the next guess by finding the square root of the remaining whatsLeft
const sq = num * num
const next = whatsLeft - sq
const guess = Math.floor (Math.sqrt (next))
return decompose (guess, next, ...) || decompose (num - 1, whatsLeft, ...)
Now it can be used to calculate values where num is huge
console.log (sumSquares(123456))
// [ 1, 2, 7, 29, 496, 123455 ]
But notice there's a bug for certain inputs. The squares of the solution still sum to the correct amount, but it's allowing some numbers to be repeated
console.log (sumSquares(50))
// [ 1, 1, 4, 9, 49 ]
To enforce the strictly increasing requirement, we have to ensure that a calculated guess is still lower than the previous. We can do that using Math.min
const guess = Math.floor (Math.sqrt (next))
const guess = Math.min (num - 1, Math.floor (Math.sqrt (next)))
Now the bug is fixed
console.log (sumSquares(50))
// [ 1, 1, 4, 9, 49 ]
// [ 1, 3, 5, 8, 49 ]
Full program demonstration
function sumSquares (n) {
function decompose (num, whatsLeft, result) {
if (whatsLeft === 0)
return result;
if (whatsLeft < 0 || num === 0)
return null;
const sq = num * num
const next = whatsLeft - sq
const guess = Math.min (num - 1, Math.floor (Math.sqrt (next)))
return decompose(guess, next, [num].concat(result)) || decompose(num-1, whatsLeft, result);
}
return decompose(n-1, n*n, []);
}
console.log (sumSquares(50))
// [ 1, 3, 5, 8, 49 ]
console.log (sumSquares(123456))
// [ 1, 2, 7, 29, 496, 123455 ]

Sign reverse does not work

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)

How to go about a d-smooth sequence algorithm

I'm really struggling to design an algorithm to find d, which is the lowest value that can be added or subtracted (at most) to make a given sequence strictly increasing.
For example.. say seq[] = [2,4,8,3,1,12]
given that sequence, the algorithm should return "5" as d because you can add or subtract at most 5 to each element such that the function is strictly increasing.
I've tried several approaches and can't seem to get a solid technique down.
I've tried looping through the seq. and checking if seq[i] < seq[i+1]. If not, it checks if d>0.. if it is, try to add/subtract it from seq[i+1]. Otherwise it calculates d by taking the difference of seq[i-1] - seq[i].
I can't get it to be stable though and Its like I keep adding if statements that are more "special cases" for unique input sequences. People have suggested using a binary search approach, but I can't make sense of applying it to this problem.
Any tips and suggestions are greatly appreciated. Thanks!
Here's my code in progress - using Python - v4
def ComputeMaxDelta3(seq):
# Create a copy to speed up comparison on modified values
aItems = seq[1:] #copies sequence elements from 1 (ignores seq[0])
# Will store the fix values for every item
# this should allocate 'length' times the 0 value
fixes = [0] * len(aItems)
print("fixes>>",fixes)
# Loop until no more fixes get applied
bNeedFix = True
while(bNeedFix):
# Hope will have no fix this turn
bNeedFix = False
# loop all subsequent item pairs (i should run from 0 to length - 2)
for i in range(0,len(aItems)-1):
# Left item
item1 = aItems[i]
# right item
item2 = aItems[i+1]
# Compute delta between left and right item
# We remember that (right >= left + 1
nDelta = item2 - (item1 + 1)
if(nDelta < 0):
# Fix the right item
fixes[i+1] -= nDelta
aItems[i+1] -= nDelta
# Need another loop
bNeedFix = True
# Compute the fix size (rounded up)
# max(s) should be int and the division should produce an int
nFix = int((max(fixes)+1)/2)
print("current nFix:",nFix)
# Balance all fixes
for i in range(len(aItems)):
fixes[i] -= nFix
print("final Fixes:",fixes)
print("d:",nFix)
print("original sequence:",seq[1:])
print("result sequence:",aItems)
return
Here's whats displayed:
Working with: [6, 2, 4, 8, 3, 1, 12]
[0]= 6 So the following numbers are the sequence:
aItems = [2, 4, 8, 3, 1, 12]
fixes>> [0, 0, 0, 0, 0, 0]
current nFix: 6
final Fixes: [-6, -6, -6, 0, 3, -6]
d: 1
original sequence: [2, 4, 8, 3, 1, 12]
result sequence: [2, 4, 8, 9, 10, 12]
d SHOULD be: 5
done!
~Note~
I start at 1 rather than 0 due to the first element being a key
As anticipated, here is (or should be) the Python version of my initial solution:
def ComputeMaxDelta(aItems):
# Create a copy to speed up comparison on modified values
aItems = aItems[:]
# Will store the fix values for every item
# this should allocate 'length' times the 0 value
fixes = [0] * len(aItems)
# Loop until no more fixes get applied
bNeedFix = True
while(bNeedFix):
# Hope will have no fix this turn
bNeedFix = False
# loop all subsequent item pairs (i should run from 0 to length - 2)
for i in range(0,len(aItems)-1):
# Left item
item1 = aItems[i]
# right item
item2 = aItems[i+1]
# Compute delta between left and right item
# We remember that (right >= left + 1
nDelta = item2 - (item1 + 1)
if(nDelta < 0):
# Fix the right item
fixes[i+1] -= nDelta
aItems[i+1] -= nDelta
# Need another loop
bNeedFix = True
# Compute the fix size (rounded up)
# max(s) should be int and the division should produce an int
nFix = (max(fixes)+1)/2 # corrected from **(max(s)+1)/2**
# Balance all fixes
for i in range(len(s)):
fixes[i] -= nFix
print("d:",nFix) # corrected from **print("d:",nDelta)**
print("s:",fixes)
return
I took your Python and fixed in order to operate exactly as my C# solution.
I don't know Python, but looking for some reference on the web, I should have found the points where your porting was failing.
If you compare your python version with mine you should find the following differences:
You saved a reference aItems into s and used it as my fixes, but fixes was meant to start as all 0.
You didn't cloned aItems over itself, then every alteration to its items was reflected outside of the method.
Your for loop was starting at index 1, whereas mine started at 0 (the very first element).
After the check for nDelta you subtracted nDelta from both s and aItems, but as I stated at points 1 and 2 they were pointing to the same items.
The ceil instruction was unnedeed because the division between two integers produces an integer, as with C#.
Please remember that I fixed the Python code basing my knowledge only on online documentation, because I don't code in that language, so I'm not 100% sure about some syntax (my main doubt is about the fixes declaration).
Regards,
Daniele.
Here is my solution:
public static int ComputeMaxDelta(int[] aItems, out int[] fixes)
{
// Create a copy to speed up comparison on modified values
aItems = (int[])aItems.Clone();
// Will store the fix values for every item
fixes = new int[aItems.Length];
// Loop until no more fixes get applied
var bNeedFix = true;
while (bNeedFix)
{
// Hope will have no fix this turn
bNeedFix = false;
// loop all subsequent item pairs
for (int ixItem = 0; ixItem < aItems.Length - 1; ixItem++)
{
// Left item
var item1 = aItems[ixItem];
// right item
var item2 = aItems[ixItem + 1];
// Compute delta between left and right item
// We remember that (right >= left + 1)
var nDelta = item2 - (item1 + 1);
if (nDelta < 0)
{
// Fix the right item
fixes[ixItem + 1] -= nDelta;
aItems[ixItem + 1] -= nDelta;
//Need another loop
bNeedFix = true;
}
}
}
// Compute the fix size (rounded up)
var nFix = (fixes.Max() + 1) / 2;
// Balance all fixes
for (int ixItem = 0; ixItem < aItems.Length; ixItem++)
fixes[ixItem] -= nFix;
return nFix;
}
The function returns the maximum computed fix gap.
As a bounus, the parameter fixes will receive the fixes for every item. These are the delta to apply to each source value in order to be sure that they will be in ascending order: some fix can be reduced but some analysis loop is required to achieve that optimization.
The following is a code to test the algorithm. If you set a breakpoint at the end of the loop, you'll be able to check the result for sequence you provided in your example.
var random = new Random((int)Stopwatch.GetTimestamp());
for (int ixLoop = -1; ixLoop < 100; ixLoop++)
{
int nCount;
int[] aItems;
// special case as the provided sample sequence
if (ixLoop == -1)
{
aItems = new[] { 2, 4, 8, 3, 1, 12 };
nCount = aItems.Length;
}
else
{
// Generates a random amount of items based on my screen's width
nCount = 4 + random.Next(21);
aItems = new int[nCount];
for (int ixItem = 0; ixItem < nCount; ixItem++)
{
// Keep the generated numbers below 30 for easier human analysis
aItems[ixItem] = random.Next(30);
}
}
Console.WriteLine("***");
Console.WriteLine(" # " + GetText(Enumerable.Range(0, nCount).ToArray()));
Console.WriteLine(" " + GetText(aItems));
int[] aFixes;
var nFix = ComputeMaxDelta(aItems, out aFixes);
// Computes the new values, that will be always in ascending order
var aNew = new int[aItems.Length];
for (int ixItem = 0; ixItem < aItems.Length; ixItem++)
{
aNew[ixItem] = aItems[ixItem] + aFixes[ixItem];
}
Console.WriteLine(" = " + nFix.ToString());
Console.WriteLine(" ! " + GetText(aFixes));
Console.WriteLine(" > " + GetText(aNew));
}
Regards,
Daniele.

Resources