aticio / renko

Renko chart creator.
MIT License
19 stars 7 forks source link

How to calculate stoploss? #5

Closed dsstex closed 2 years ago

dsstex commented 2 years ago

@aticio

Thanks for the library. It is minimal and good.

I would like to have a stoploss value of half of the brick size.

Risk:Reward ratio is 0.5:1. So if the brick size is 100, then I would like to have 50 as stoploss. I'm really confused about the low value in this library.

When I enter a trade, it is usually based on the close_price of the last_brick. However, the low value in this library is calculated based on the open_price of the last_brick. So I believe it is not possible to use the low value as stoploss in my case.

You have any solution for that?

Thanks

dsstex commented 2 years ago

@aticio

One more thing: Last week, we tried to generate renko bricks using pandas.

https://stackoverflow.com/questions/71909107/pandas-resample-data-by-a-non-timeseries-column-e-g-price

But I believe the solution is not working properly. If you can make it work, then integrate it in your library.

Thanks

dsstex commented 2 years ago

When the last direction is up,

your code has two if checks for calculating low, high values.

  1. if current_price > last_brick["close"]: do_something

  2. elif current_price < last_brick["open"]: do_something

I think we need a third scenario.

  1. elif current_price < last_brick["close"] and current_price > last_brick["open"]:
aticio commented 2 years ago

Hi,

low and high values are the wicks for that particular brick. In the link below, you can find an explanatory image of these wicks.

https://github.com/aticio/renko/issues/2#issuecomment-1002424952=

For your case, the corresponding low and high values are not suitable for stop loss and take profit use. When you open a new position (e.g. long), simply take the opening value of the brick you expect to be formed (or the closing value of the completed brick). Then subtract the half brick size from this value and you will find the stop loss point you want.

For example opening a long position: stop_loss = open - (brick_size / 2)


I'm not 100% sure, but brick building may have a different logic than resampling. You can do this with this library. As a matter of fact, I already use it this way in my own bot.

# close: list of close prices or tick prices (or whatever list of numbers you gave)
# 1000: brick size you choose
rnk = Renko(1000, close)
rnk.create_renko()
rnk.draw_chart()

print(rnk.bricks)

I'm not sure I fully understand, but anyway, the condition in the third item here coincides with the brick's own spawn area. low and high values must be outside the body range of the brick.

Please let me know if I misunderstood or if there is anything else you are wondering about.

Thanks.

dsstex commented 2 years ago

Thanks for the explanation.

For your case, the corresponding low and high values are not suitable for stop loss and take profit use.
When you open a new position (e.g. long), simply take the opening value of the brick you expect to be formed (or the closing value of the completed brick). Then subtract the half brick size from this value and you will find the stop loss point you want.

For example opening a long position:
stop_loss = open - (brick_size / 2)

Makes sense.

I'm not 100% sure, but brick building may have a different logic than resampling.

Got it.

I'm not sure I fully understand, but anyway, the condition in the third item here coincides with the brick's own spawn area. low and high values must be outside the body range of the brick.

Please let me know if I misunderstood or if there is anything else you are wondering about.

I usually calculate profit and loss using this page. https://www.winrate.io/

I trade in binance futures and I usually use market order for both entry and exit. Which is 0.04% in my case. winrate.io, doesn't have calculation for "binance futures". So I usually select the exchange "Huobi" from the dropdown since it has the same fee structure as "binance futures".

And then finally I click "Advanced settings", set the value "Market" for both "Entry Trade Order Type" and "Take Profit Order Type".

So the total fee per trade for me is 0.04 + 0.04 = 0.08%.

This is the full settings for https://www.winrate.io/

Starting Balance USD: 1000
Win Rate %: 60
Take Profit %: 0.5
Stop Loss %: 0.4
Number of Trades: 100
Leverage: 20
Exchange: Huobi
Limit Order Fee %: 0.02
Market Order Fee %: 0.04

Advanced Settings:
Max Position Size USD: 100000
Randomize Trades Order: Yes
Entry Trade Order Type: Market
Take Profit Order Type: Market
Stop Loss Order Type: Market
Additional Order Cost %: 0

This is how Profit and Loss look like based on Stop Loss.

Take Profit %           Stop Loss %                         Profit/Loss

0.5                           0.5                                      -88 USD
0.5                           0.45                                    +430 USD
0.5                           0.4                                      +1231 USD
0.5                           0.35                                    +2464 USD
0.5                           0.3                                      +4353 USD
0.5                           0.25                                    +6623 USD

As you can see, the single most factor that influence the Profit and Loss is the Stop Loss percentage.

At the moment, I'm building renko bricks daily based on the last day midnight price. So if the BTC price is 45000 USD last day midnight, I add 5% to it. Which means 45000 + 2250 = 47250

I then calculate brick size using the value 0.5%.

0.5% of 47250 = 236.25.

I think an option to automatically calculate brick size based on the last close value in percentage will be really helpful in cases like this.

Also a fixed brick size is a traditional method. Modern method relies on ATR. So you should add that option since people usually look for that option.

This is how you calculate ATR on a candlestick.

data['high-low'] = abs(data['high'] - data['low'])
data['high-pc'] = abs(data['high'] - data['close'].shift(1))
data['low-pc'] = abs(data['low'] - data['close'].shift(1))
data['true-range'] = data[['high-low', 'high-pc', 'low-pc']].max(axis=1, skipna=False)
data['atr'] = data['true-range'].rolling(14).mean()

Coming back to the stop loss, It seems like renko bricks has the 1:2 ratio for profit:stoploss.

Let's say the brick size is 100, and last brick direction is UP, and the last brick close price is 45000 USD, an UP brick get generated when the price moves to 45100 USD. But the DOWN brick get generated only when the price goes down 200 USD. i.e 44800 USD.

Is that right?

I understand I can use stop_loss = open - (brick_size / 2) to calculate stoploss. However, I'm more concerned about whether that stoploss would be optimal. There is no way to understand that without doing any backtesting.

So it would be ideal for me to have a separate low_wick and high_wick values for stoploss. Let's term that as "sl_low_wick" and "sl_high_wick".

Here are the scenario I understand in your code when the last brick direction is UP. https://github.com/aticio/renko/blob/main/renko.py#L26

Last direction: UP

When the price is above last_close price, calculate high_wick. But a new UP brick formed, use only low_wick.
When the price is below last_open price, calculate low_wick. But a new DOWN brick formed, use only high_wick.

So any high_wick value and low_wick value greater than 0 would be also greater than the brick_size.

In other words,

When the last brick close price is 45500 USD, a low_wick doesn't get calculated when the price is between 45500 to 45400. It gets calculated only when the price goes below 45400.

I just need a way to calculate sl_low_wick and sl_high_wick, but it focuses only on the price between 45500 to 45400 / 45500 to 45600.

Do let me know if you have any solutions. Also do let me know if you want any clarification.

Thanks. Appriciate your time.

aticio commented 2 years ago

Hi,

I have no experience with futures market so I can't give much technical ideas. What I will say next is only my sincere opinion. winrate.io could be a good tool but single tests won't get you very far. The claim that stop loss value alone is effective may be valid only for this test.

There are very important traders that don't care that much about stop losses: Cycle Analytics for Traders: Advanced Technical Trading Concepts 1st Edition by John F. Ehlers page 225


There are other critical ratios based on your approach of strategy such as: max_drawdown_rate risk_reward_ratio profit_factor and the one I called ehlers_ratio = (2 (win_rate / 100) - 1) profit_factor https://github.com/aticio/testwise/blob/main/testwise.py#L469=


With renko, it is almost impossible to catch ups and downs with daily data. Although the graphics look very nice with daily close prices, it is misleading and Renko works most accurately with tick data. Binance provides websocket market streams, so you can get tick data with second precision:

https://binance-docs.github.io/apidocs/spot/en/#individual-symbol-mini-ticker-stream=


To me, brick size is one of the most critical issues in Renko. I've tried calculating this size with atr before. I've even used a scenario where this size changes dynamically. My other library provides ATR calculation as well: https://github.com/aticio/legitindicators

But I prefer traditional method for renko. Here is why: https://towardsdatascience.com/renko-brick-size-optimization-34d64400f60e


1:2 ratio is correct.


I would not recommend using backtest to find the optimal stop loss value. Testing is a very cutting edge subject. After the first test, the concept of bias comes into play.

Checkout: Advances in Financial Machine Learning 1st Edition, by Marcos López de Prado Chapter 11: The Dangers of Backtesting

Also another good content: How to avoid trading strategies that degrade quickly" - Timothy Masters


You only need to calculate stop loss value once. After that, it's more of a follow-up job than a calculation. That is why you need tick data especially if you are using market orders. Let's say you calculated that the stop loss price is 45600 with a long position. Then you can open a websocket connection to binance and follow the price with 1000 ms precision. When the price is below 45600, execute the order. If you try to do this with daily closing prices, your strategy will be shattered and you could incur big losses.

These are my opinions. I hope I could be of help.

Thanks.

dsstex commented 2 years ago

Thanks for the book reference. I'll check it out.

Also thanks for your other libraries testwise and legitindicators. I'll give it a try.

With renko, it is almost impossible to catch ups and downs with daily data. Although the graphics look very nice with daily close prices, it is misleading and Renko works most accurately with tick data.
Binance provides websocket market streams, so you can get tick data with second precision:

https://binance-docs.github.io/apidocs/spot/en/#individual-symbol-mini-ticker-stream=

I don't use daily close prices to build renko. But use it only to calculate the brick size.

Since renko care about price, I usually use binance aggtrades for generating bricks. https://data.binance.vision/?prefix=data/futures/um/daily/aggTrades/BTCUSDT/

A raw trade is strictly defined as 1 taker and 1 maker trading some quantity at a price, but an aggregate trade is defined as 1 taker, n makers, trading the sum of all the individual raw trade quantities at a price.

There are other critical ratios based on your approach of strategy such as:
max_drawdown_rate
risk_reward_ratio
profit_factor
and the one I called ehlers_ratio = (2 * (win_rate / 100) - 1) * profit_factor
https://github.com/aticio/testwise/blob/main/testwise.py#L469=

I have backtested my code multiple times. I'm getting a 60% to 67% win rate. However since renko has profit:stoploss ratio of 1:2, my 33% loss is actually a 66% loss. If you add exchange fees, then it gets worse.

To me, brick size is one of the most critical issues in Renko. I've tried calculating this size with atr before. I've even used a scenario where this size changes dynamically.
My other library provides ATR calculation as well: https://github.com/aticio/legitindicators

But I prefer traditional method for renko. Here is why:
https://towardsdatascience.com/renko-brick-size-optimization-34d64400f60e

I have skimmed through this article. https://towardsdatascience.com/renko-brick-size-optimization-34d64400f60e

I'll read it carefully later.

I would not recommend using backtest to find the optimal stop loss value. Testing is a very cutting edge subject. After the first test, the concept of bias comes into play.

Checkout:
Advances in Financial Machine Learning 1st Edition,
by Marcos López de Prado
Chapter 11: The Dangers of Backtesting

Also another good content:
[How to avoid trading strategies that degrade quickly" - Timothy Masters](https://www.youtube.com/watch?v=1RKz9v_0WDo&t=74s)

Thanks for the links.

You only need to calculate stop loss value once. After that, it's more of a follow-up job than a calculation. That is why you need tick data especially if you are using market orders.
Let's say you calculated that the stop loss price is 45600 with a long position. Then you can open a websocket connection to binance and follow the price with 1000 ms precision. When the price is below 45600, execute the order.
If you try to do this with daily closing prices, your strategy will be shattered and you could incur big losses.

As I mentioned earlier, I'm using aggtrades data. Not daily close price. Sorry for the confusion.

These are my opinions. I hope I could be of help.

Yes, it is very helpful.

If you don't mind me asking, how exactly are you managing risks in renko? Are you using a fixed stoploss? or something different?

Thanks

aticio commented 2 years ago

I have backtested my code multiple times. I'm getting a 60% to 67% win rate. However since renko has profit:stoploss ratio of 1:2, my 33% loss is actually a 66% loss. If you add exchange fees, then it gets worse.

That is why you should always consider the profit factor as well, if you're using win rate as your approval ratio, Because at first sight, %0.5 stop loss looks very sharp and could give you some trouble (early stops).

Checkout: https://www.youtube.com/watch?v=zkKgyad9RFA&t=2225s

You should also consider walkforward testing and live testing as well to be absolutely sure.


I think the best thing about using Renko is risk management. It's so easy that you can use only bricks to decide profit and stop levels. However, I don't use them. The bot is always in position long or short (statistically more profitable - see this book by Kevin J. Davey Simply one green brick means long and one red means short. There are some cases that I don't open positions based on the market situation (sideways mostly).

Other than that, I'm not making a definitive judgment yet, and I've done thousands of tests with dozens of strategies but I think backtesting is losing its importance with renko. It becomes more of a market reading and brick size optimization thing.

dsstex commented 2 years ago

Thanks.

Appreciate your feedback.

I'll open more tickets if I face any issues with your library.

Have a nice day.

aticio commented 2 years ago

My pleasure. I'll try to help as much as I can.

Thanks.