Draw line below/above line.new - pivot

Here is a script i'm using for detecting pivot point.
I'd like to draw a line at the close of the new detected pivot point, each time new pivot point are detected (and deleting other lines)
i try to change the line.new value to get the "close" but it didn't work
See the picture below, the blue lines i draw is what i'm searching to do :D
enter image description here
indicator("Pivot Points", overlay=true)
// Get user input
var devTooltip = "Deviation is a multiplier that affects how much the price should deviate from the previous pivot in order for the bar to become a new pivot."
var depthTooltip = "The minimum number of bars that will be taken into account when analyzing pivots."
threshold_multiplier = input.float(title="Deviation", defval=2.5, minval=0, tooltip=devTooltip)
depth = input.int(title="Depth", defval=10, minval=1, tooltip=depthTooltip)
deleteLastLine = input.bool(title="Delete Last Line", defval=false)
bgcolorChange = input.bool(title="Change BgColor", defval=false)
// Calculate deviation threshold for identifying major swings
dev_threshold = ta.atr(10) / close * 100 * threshold_multiplier
// Prepare pivot variables
var line lineLast = na
var int iLast = 0 // Index last
var int iPrev = 0 // Index previous
var float pLast = 0 // Price last
var isHighLast = false // If false then the last pivot was a pivot low
// Custom function for detecting pivot points (and returning price + bar index)
pivots(src, length, isHigh) =>
l2 = length * 2
c = nz(src[length])
ok = true
for i = 0 to l2
if isHigh and src[i] > c // If isHigh, validate pivot high
ok := false
if not isHigh and src[i] < c // If not isHigh, validate pivot low
ok := false
if ok // If pivot is valid, return bar index + high price value
[bar_index[length], c]
else // If pivot is invalid, return na
[int(na), float(na)]
// Get bar index & price high/low for current pivots
[iH, pH] = pivots(high, depth / 2, true)
[iL, pL] = pivots(low, depth / 2, false)
// Custom function for calculating price deviation for validating large moves
calc_dev(base_price, price) => 100 * (price - base_price) / price
// Custom function for detecting pivots that meet our deviation criteria
pivotFound(dev, isHigh, index, price) =>
if isHighLast == isHigh and not na(lineLast) // Check bull/bear direction of new pivot
// New pivot in same direction as last (a pivot high), so update line upwards (ie. trend-continuation)
if isHighLast ? price > pLast : price < pLast // If new pivot is above last pivot, update line
line.set_xy2(lineLast, index, price)
[lineLast, isHighLast]
else
[line(na), bool(na)] // New pivot is not above last pivot, so don't update the line
else // Reverse the trend/pivot direction (or create the very first line if lineLast is na)
if math.abs(dev) > dev_threshold
// Price move is significant - create a new line between the pivot points
id = line.new(iLast, pLast, index, price, color=color.gray, width=1, style=line.style_dashed)
[id, isHigh]
else
[line(na), bool(na)]
// If bar index for current pivot high is not NA (ie. we have a new pivot):
if not na(iH)
dev = calc_dev(pLast, pH) // Calculate the deviation from last pivot
[id, isHigh] = pivotFound(dev, true, iH, pH) // Pass the current pivot high into pivotFound() for validation & line update
if not na(id) // If the line has been updated, update price & index values and delete previous line
if id != lineLast and deleteLastLine
line.delete(lineLast)
lineLast := id
isHighLast := isHigh
iPrev := iLast
iLast := iH
pLast := pH
else
if not na(iL) // If bar index for current pivot low is not NA (ie. we have a new pivot):
dev = calc_dev(pLast, pL) // Calculate the deviation from last pivot
[id, isHigh] = pivotFound(dev, false, iL, pL) // Pass the current pivot low into pivotFound() for validation & line update
if not na(id) // If the line has been updated, update price values and delete previous line
if id != lineLast and deleteLastLine
line.delete(lineLast)
lineLast := id
isHighLast := isHigh
iPrev := iLast
iLast := iL
pLast := pL
**// Get starting and ending high/low price of the current pivot line
startIndex = line.get_x1(lineLast)
startPrice = line.get_y1(lineLast)
endIndex = line.get_x2(lineLast)
endPrice = line.get_y2(lineLast)
// Draw top & bottom of impulsive move
topLine = line.new(startIndex, startPrice, endIndex, startPrice, extend=extend.right, color=color.red)
bottomline = line.new(startIndex, endPrice, endIndex, endPrice, extend=extend.right, color=color.green)
line.delete(topLine[1])
line.delete(bottomline[1])**
//plot(startPrice, color=color.green)
//plot(endPrice, color=color.red)
// Do what you like with these pivot values :)
// Keep in mind there will be an X bar delay between pivot price values updating based on Depth setting
dist = math.abs(startPrice - endPrice)
plot(dist, color=color.new(color.purple,100))
bullish = endPrice > startPrice
offsetBG = -(depth / 2)
bgcolor(bgcolorChange ? bullish ? color.new(color.green,90) : color.new(color.red,90) : na, offset=offsetBG)
Thank you
Changing the code
**// Get starting and ending high/low price of the current pivot line
startIndex = line.get_x1(lineLast)
startPrice = line.get_y1(lineLast)
endIndex = line.get_x2(lineLast)
endPrice = line.get_y2(lineLast)
// Draw top & bottom of impulsive move
topLine = line.new(startIndex, startPrice, endIndex, startPrice, extend=extend.right, color=color.red)
bottomline = line.new(startIndex, endPrice, endIndex, endPrice, extend=extend.right, color=color.green)
line.delete(topLine[1])
line.delete(bottomline[1])**

Related

How to force a waiting time of a few seconds between execution of commands in Pine? Need cooldown between close and open possition

A simple strategy script sends alerts to open and exit trades, that need to switch between long and short when conditions are met.
Problem: Two alerts (e.g. exit short / enter long) are generated one after the other. Enter long fails, as the previous short deal didn't have time to close.
Question: How can I delay script execution by 5-10 seconds?
Have tried Utilities.sleep(10000), but it does not compile.
*I am a complete beginner, and looking for a simple answer. Hope there is one :]
Here the code:
'''
strategy("My Strategy", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=15)
////////////
// Inputs //
length = input(100)
mult = input(2.0)
message_long_entry = input("long entry message")
message_long_exit = input("long exit message")
message_short_entry = input("short entry message")
message_short_exit = input("short exit message")
atrPeriod = input(10, "ATR Length")
factor = input.float(3.0, "Factor", step = 0.01)
[_, direction] = ta.supertrend(factor, atrPeriod)
if ta.change(direction) < 0
strategy.entry("My Long Entry Id", strategy.long, when = barstate.isconfirmed)
alert(message_short_exit)
/// Utilities.sleep(10000) <--- Delay needed here
alert(message_long_entry)
if ta.change(direction) > 0
strategy.entry("My Short Entry Id", strategy.short, when = barstate.isconfirmed)
alert(message_long_exit)
/// Utilities.sleep(10000) <--- Delay needed here
alert(message_short_entry)
'''
You can use this example from Pinecoders FAQ
//#version=5
strategy('Strat with time delay', overlay=true)
i_qtyTimeUnits = -input.int(20, 'Quantity', inline='Delay', minval=0, tooltip='Use 0 for no delay')
i_timeUnits = input.string('minutes', '', inline='Delay', options=['seconds', 'minutes', 'hours', 'days', 'months', 'years'])
// ————— Converts current chart timeframe into a float minutes value.
f_tfInMinutes() =>
_tfInMinutes = timeframe.multiplier * (timeframe.isseconds ? 1. / 60 : timeframe.isminutes ? 1. : timeframe.isdaily ? 60. * 24 : timeframe.isweekly ? 60. * 24 * 7 : timeframe.ismonthly ? 60. * 24 * 30.4375 : na)
_tfInMinutes
// ————— Calculates a +/- time offset in variable units from the current bar's time or from the current time.
// WARNING:
// This functions does not solve the challenge of taking into account irregular gaps between bars when calculating time offsets.
// Optimal behavior occurs when there are no missing bars at the chart resolution between the current bar and the calculated time for the offset.
// Holidays, no-trade periods or other irregularities causing missing bars will produce unpredictable results.
f_timeFrom(_from, _qty, _units) =>
// _from : starting time from where the offset is calculated: "bar" to start from the bar's starting time, "close" to start from the bar's closing time, "now" to start from the current time.
// _qty : the +/- qty of _units of offset required. A "series float" can be used but it will be cast to a "series int".
// _units : string containing one of the seven allowed time units: "chart" (chart's resolution), "seconds", "minutes", "hours", "days", "months", "years".
// Dependency: f_resInMinutes().
int _timeFrom = na
// Remove any "s" letter in the _units argument, so we don't need to compare singular and plural unit names.
_unit = str.replace_all(_units, 's', '')
// Determine if we will calculate offset from the bar's time or from current time.
_t = _from == 'bar' ? time : _from == 'close' ? time_close : timenow
// Calculate time at offset.
if _units == 'chart'
// Offset in chart res multiples.
_timeFrom := int(_t + f_tfInMinutes() * 60 * 1000 * _qty)
_timeFrom
else
// Add the required _qty of time _units to the _from starting time.
_year = year(_t) + (_unit == 'year' ? int(_qty) : 0)
_month = month(_t) + (_unit == 'month' ? int(_qty) : 0)
_day = dayofmonth(_t) + (_unit == 'day' ? int(_qty) : 0)
_hour = hour(_t) + (_unit == 'hour' ? int(_qty) : 0)
_minute = minute(_t) + (_unit == 'minute' ? int(_qty) : 0)
_second = second(_t) + (_unit == 'econd' ? int(_qty) : 0)
// Return the resulting time in ms Unix time format.
_timeFrom := timestamp(_year, _month, _day, _hour, _minute, _second)
_timeFrom
// Entry conditions.
ma = ta.sma(close, 100)
goLong = close > ma
goShort = close < ma
// Time delay filter
var float lastTradeTime = na
if nz(ta.change(strategy.position_size), time) != 0
// An order has been executed; save the bar's time.
lastTradeTime := time
lastTradeTime
// If user has chosen to do so, wait `i_qtyTimeUnits` `i_timeUnits` between orders
delayElapsed = f_timeFrom('bar', i_qtyTimeUnits, i_timeUnits) >= lastTradeTime
if goLong and delayElapsed
strategy.entry('Long', strategy.long, comment='Long')
if goShort and delayElapsed
strategy.entry('Short', strategy.short, comment='Short')
plot(ma, 'MA', goLong ? color.lime : color.red)
plotchar(delayElapsed, 'delayElapsed', '•', location.top, size=size.tiny)
What worked for me was just adding a while loop in my webhook side code checking if there is in realtime an active trade. Im using binance so through postman i accessed to GET /fapi/v2/positionRisk which shows you your current positions information which shows like this:
[
{
"symbol": "BTCUSDT",
"positionAmt": "0.000",
"entryPrice": "0.0",
"markPrice": "22615.15917559",
"unRealizedProfit": "0.00000000",
"liquidationPrice": "0",
"leverage": "10",
"maxNotionalValue": "20000000",
"marginType": "isolated",
"isolatedMargin": "0.00000000",
"isAutoAddMargin": "false",
"positionSide": "BOTH",
"notional": "0",
"isolatedWallet": "0",
"updateTime": 165963
} ]
so accessing your current positions amount:
check = float(client.futures_position_information(symbol="BTCUSDT")[0]["positionAmt"])
note if you have hedge mode activated you would have to check from both your long or short side positions changing through [0] or [1] depending on which side you need.
now you can just add the loop before any of your entries:
while check != 0:
check = float(client.futures_position_information(symbol="BTCUSDT")[0]["positionAmt"])
order = client.futures_create_order(symbol=symbol, side=side, type=order_type, quantity=quantity) //this is your entry after loop breaks
this will delay any of your entries with the loop always updating and checking your current position amount until all of your positions are closed which will make it 0, breaking, and then allowing the code to keep going and start a new position in this case

Autofill space up to fixed Column width on each line

I am trying to set the column width of each line to a fixed "511" width on a large dataset. If the line has less than 511 column width then I want to add space on the end of the line until it has 511 column width. Currently, I am running into a lot of the entries that have irregular column widths. For instance, if the column width is 450 i.e. less than than 511 then I am manually adding space until it has 511 width and if column width exceeds 511 then I am deleting space until it is 511. The current dataset has over 1 million rows so I was wondering if there was faster way to add "spaces" on the end of each line. Would appreciate any help.
Sample of irregular column width
If there aren't many irregular lines (if most lines are 511 characters long), you can use this macro. Otherwise, this macro might take a long time to finish.
COLUMN = 511 + 1; // add 1 to the width
Redraw = false;
nLines = document.GetLines();
for( y = 1; y <= nLines; ++y ) {
document.selection.SetActivePoint( eePosLogical, 1, y );
document.selection.EndOfLine( false, eeLineLogical );
x = document.selection.GetActivePointX( eePosLogical );
if( x < COLUMN ) {
s = "";
for( i = COLUMN - x ; i > 0; --i ) {
s += " ";
}
document.selection.Text = s;
}
else if( x > COLUMN ) {
document.selection.SetActivePoint( eePosLogical, COLUMN, y, true );
document.selection.Delete();
}
}
To run this, save this code as, for instance, AutoSpace.jsee, and then select this file from Select... in the Macros menu. Finally, select Run AutoSpace.jsee in the Macros menu.

How to access the last indicator values

I've got an indicator which shows pivot points:
//#version=4
study("Trend", overlay=false)
leftBars = input(3)
rightBars = input(3)
ph = pivothigh(high, leftBars, rightBars)
pl = pivotlow(low, leftBars, rightBars)
How can I check if the last ph was higher than the ph before? (I'd like to check for an uptrend or downtrend)
You can try the following code (including your original, as you see):
//#version=4
study("Trend", overlay=false)
leftBars = input(3)
rightBars = input(3)
ph = pivothigh(high, leftBars, rightBars)
pl = pivotlow(low, leftBars, rightBars)
//INIT VARIABLES
var int ph_uptrend_flag = 0
var float ph_valid = 0
var float ph_valid_old = 1e99 // use any very high non meaningful number here for initialization only
ph_non_na = nz(ph,0) // stores 0's instead of na's for non-pivot-pointed bars
// re-calculate uptrend flag every time a new pivot comes in, otherwise keep last known value for uptrend flag
if ph_non_na != 0
ph_valid := ph_non_na
ph_uptrend_flag := ph_valid > ph_valid_old ? 1 : 0
ph_valid_old := ph_valid
else
ph_valid := ph_valid
ph_valid_old := ph_valid_old
//plot uptrend flag and mark background accordingly
plot(ph_uptrend_flag,title="ph uptrend indication",linewidth=4,color=color.white)
//plot(ph,title="ph value",color=color.lime,style=8) //plot ph values (better used with overlay=true)

How can I replace automatically-generated grand total values with different ones (Aspose Cells)?

My spreadsheet automatically generates a "Grand Totals" column as the rightmost column:
This is nice, in general. But in specific, I've got a couple of problems with it: The last two values (with the unfortunate labels "Sum of Avg Price" and "Sum of Percentage") provide just that - a sum of the previous columns. In those cases, I don't want a simple sum, but an average in the first case and a percentage in the second case.
For the AvgPrice, what I need is a calculation of "Sum of Total Price" / "Sum of Total Quty" in the Grand Total column. For instance, the first AvgPrice Grand Total value should be "33.14" rather than "66.26"
For the Percentage, I need the percentage of Total Price for the item/Description (such as "25151.75" seen in the first item above) as compared to the "Total Price" value in the "Total Sum of Total Price" grand total row/column ("1529802.82"). That value is seen here:
So the "Percentage" value for that first item ("ASPARAGUS, LARGE 11/1#") should be approximately 1.6 (as 25151.75 is about 1/60th of 1529802.82), rather than 1.36.
Is there a way to set this up to automatically generate those values in the Grand Total Column, or do I need to prevent the Grand Total column from being generated like so:
pivotTable.ColumnGrand = false;
...and then add that column to the sheet manually, doing the calculations in code, and adding those values that way?
In order to look into this issue in detail, please post your query in Aspose.Cells forum with your sample excel files. You can provide us source excel file, actual output excel file and the expected excel file and sample code. And the screenshot like you provided will also be helpful. Thanks for your cooperation in this regard.
Aspose.Cells Forum Link:
https://www.aspose.com/community/forums/aspose.cells-product-family/19/showforum.aspx
Note: I am working as Developer Evangelist at Aspose
It's easiest, I think, to just add that column manually, calculating the necessary values; here's how I'm doing it now (basically the same idea as in Excel Interop - manually adding the Grand Total column):
After the PivotTable code, I call AddManualGrandTotalColumn(), which is:
private void AddManualGrandTotalColumn()
{
var pivot = pivotTableSheet.PivotTables[0];
var dataBodyRange = pivot.DataBodyRange;
int rowsUsed = dataBodyRange.EndRow;
int FIRST_DATA_ROW = 7;
int currentQtyRow = FIRST_DATA_ROW;
int ROWS_IN_A_RANGE = 4;
// Needed?
pivot.RefreshData();
pivot.CalculateData();
// Get Total Sales value, which will be needed for computing the % val
Cell totalTotalPurchasesCell = pivotTableSheet.Cells[rowsUsed - 2, _grandTotalsColumnPivotTable + 1];
decimal totalTotalPurchases = Convert.ToDecimal(totalTotalPurchasesCell.Value);
Cell gtLabelCell = pivotTableSheet.Cells[6, _grandTotalsColumnPivotTable + 2];
gtLabelCell.Value = "Grand Total";
Cell QtyCell = null;
Cell PriceCell = null;
Cell AvgPriceCell = null;
Cell PercentageCell = null;
while (currentQtyRow < rowsUsed)
{
// SumTotalQty
int qty = GetSumTotalQty(currentQtyRow);
QtyCell = pivotTableSheet.Cells[currentQtyRow, _grandTotalsColumnPivotTable + 2];
QtyCell.Value = qty;
// SumTotalPrice
decimal price = GetSumTotalPrice(currentQtyRow+1);
PriceCell = pivotTableSheet.Cells[currentQtyRow+1, _grandTotalsColumnPivotTable + 2];
PriceCell.Value = price;
// Calculate Avg Price (SumTotalPrice / SumTotalQty)
decimal avg = 0.0M;
if ((price > 0) && (qty > 0))
{
avg = price / qty;
}
AvgPriceCell = pivotTableSheet.Cells[currentQtyRow+2, _grandTotalsColumnPivotTable + 2];
AvgPriceCell.Value = avg;
// Calculate Percentage (totalTotalPurchases / SumTotalPrice?)
decimal prcntg = 0.0M;
if ((totalTotalPurchases > 0) && (price > 0)) // ? Right calculation?
{
prcntg = totalTotalPurchases / price;
}
PercentageCell = pivotTableSheet.Cells[currentQtyRow+3, _grandTotalsColumnPivotTable + 2];
PercentageCell.Value = prcntg;
currentQtyRow = currentQtyRow + ROWS_IN_A_RANGE;
}
}
private int GetSumTotalQty(int currentQtyRow)
{
int FIRST_MONTH_COL = 2;
int LAST_MONTH_COL = _grandTotalsColumnPivotTable; // - 1;
int cumulativeQty = 0;
Cell qtyCell = null;
for (int i = FIRST_MONTH_COL; i <= LAST_MONTH_COL; i++)
{
qtyCell = pivotTableSheet.Cells[currentQtyRow, i];
cumulativeQty = cumulativeQty + Convert.ToInt32(qtyCell.Value);
}
return cumulativeQty;
}
. . . (etc. for GetSumTotalPrice())

Cassandra: Fixed number of rows in a table

I want to create a table with fixed number of rows (lets say N), where if N+1th row was added, then 1st row would be removed.
This is the table, I use for storage of last N best results from graph analysis:
CREATE TABLE IF NOT EXISTS lp_registry.best (
value float, // best value for current graph
verts int, // number of vertices in graph
edges int, // number of edges in graph
wid text, // worker id
id timeuuid, // timeuuid
PRIMARY KEY (wid, id)
) WITH CLUSTERING ORDER BY (id ASC);
I've read about expiring data at DataStax, but found only TTL expirations. So I decided to do it in following way.
My Approach A:
Everytime a new result is wanted to be added, id of oldest row is retrieved..
SELECT wid, id FROM lp_registry.best LIMIT 1;
..as well as current number of rows..
SELECT COUNT(*) FROM FROM lp_registry.best;
Consequently if count >= N, then the oldest row is removed and the newest is added...
BEGIN BATCH
INSERT INTO lp_registry.best (value, verts, edges, wid, id) VALUES (?, ?, ?, ? now());
DELETE FROM lp_registry.best WHERE wid = ? AND id = ?;
APPLY BATCH;
This approach has problem with that first selects are not atomic operations together with the following batch. So if any other worker deleted oldest row between select and batch, or N was exceeded, then this wouldn't work.
My Approach B:
Same first steps ...
SELECT wid, id FROM lp_registry.best LIMIT 1;
SELECT COUNT(*) FROM FROM lp_registry.best;
Then try to delete oldest row again and again until success..
if count < N {
INSERT INTO lp_registry.best (value, verts, edges, wid, id) VALUES (?, ?, ?, ? now());
} else {
while not success {
DELETE FROM lp_registry.best WHERE wid = ? AND id = ? IF EXISTS;
}
INSERT INTO lp_registry.best (value, verts, edges, wid, id) VALUES (?, ?, ?, ? now());
}
In this approach there is still trouble with exceeding N in the database, before count < N is checked.
Can you point me to the right solution?
Here is my solution. At first we need to create a table that will store current number of rows...
CREATE TABLE IF NOT EXISTS row_counter (
rmax int, // maximum allowed number of rows
rows int, // current number of rows
name text, // name of table
PRIMARY KEY (name)
);
Then initialize it for a given fixed-rows tables:
INSERT INTO row_counter (name, rmax, rows)
VALUES ('best', 100, 0);
These are the statements used in the following code:
q1 = "SELECT rows, rmax FROM row_counter WHERE name = 'best'";
q2 = "UPDATE row_counter SET rows = ? WHERE name = 'best' IF rows < ?";
q3 = "SELECT wid, id FROM best LIMIT 1";
q4 = "DELETE FROM best WHERE wid = ? AND id = ? IF EXISTS";
q5 = "INSERT INTO best (vertex, value, verts, edges, wid, id) VALUES (?, ?, ?, ?, ?, now())";
selectCounter = session.prepare(q1);
updateCounter = session.prepare(q2);
selectOldBest = session.prepare(q3);
deleteOldBest = session.prepare(q4);
insertNewBest = session.prepare(q5);
Solution in Java:
// Success indicator
boolean succ = false;
// Get number of registered rows in the table with best results
Row row = session.execute(selectCounter.bind()).one();
int rows = row.getInt("rows") + 1;
int rmax = row.getInt("rmax");
// Repeatedly try to reserve empty space in table
while (!succ && rows <= rmax) {
succ = session.execute(updateCounter.bind(rows, Math.min(rows, rmax))).wasApplied();
rows = session.execute(selectCounter.bind()).one().getInt("rows") + 1;
}
// If there is not empty space in table, repeatedly try to make new empty space
while (!succ) {
row = session.execute(selectOldBest.bind()).one();
succ = session.execute(deleteOldBest.bind(row.getString("wid"), row.getUUID("id"))).wasApplied();
}
// Insert new row
session.execute(insertNewBest.bind(vertex, value, verts, edges, workerCode));

Resources