应用止损
止损可在证券达到指定价格水平时自动买入或卖出。它们既能通过退出糟糕的交易来限制潜在损失,也能在证券达到目标价格时卖出以锁定利润。
本笔记本将介绍如何在 PyBroker 中模拟止损:
[1]:
import pybroker
from pybroker import Strategy, YFinance
pybroker.enable_data_source_cache("stops")
strategy = Strategy(YFinance(), "1/1/2018", "1/1/2023")
止损
止损单用于在证券价格达到或跌破指定水平时自动退出交易。例如,以下代码展示了一个在入场价格下跌 20% 处设置的止损单示例:
[2]:
def buy_with_stop_loss(ctx):
if not ctx.long_pos():
ctx.buy_shares = ctx.calc_target_shares(1)
ctx.stop_loss_pct = 20
strategy.add_execution(buy_with_stop_loss, ["TSLA"])
result = strategy.backtest()
result.trades
Backtesting: 2018-01-01 00:00:00 to 2023-01-01 00:00:00
Loading bar data...
[*********************100%***********************] 1 of 1 completed
Loaded bar data: 0:00:00
Test split: 2018-01-02 00:00:00 to 2022-12-30 00:00:00
100% (1259 of 1259) |####################| Elapsed Time: 0:00:00 Time: 0:00:00
Finished backtest: 0:00:01
[2]:
| type | symbol | entry_date | exit_date | entry | exit | shares | pnl | return_pct | agg_pnl | bars | pnl_per_bar | stop | mae | mfe | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| id | |||||||||||||||
| 1 | long | TSLA | 2018-01-03 | 2018-03-28 | 21.36 | 17.09 | 4679 | -19988.69 | -20.00 | -19988.69 | 58 | -344.63 | loss | -4.27 | 2.67 |
| 2 | long | TSLA | 2018-03-29 | 2019-05-20 | 17.31 | 13.73 | 4622 | -16546.76 | -20.68 | -36535.45 | 286 | -57.86 | loss | -3.58 | 8.52 |
锁定利润
可以使用获利单来锁定交易的利润。以下代码在入场价格上涨 10% 处添加了一个获利单:
[3]:
def buy_with_stop_loss_and_profit(ctx):
if not ctx.long_pos():
ctx.buy_shares = ctx.calc_target_shares(1)
ctx.stop_loss_pct = 20
ctx.stop_profit_pct = 10
strategy.clear_executions()
strategy.add_execution(buy_with_stop_loss_and_profit, ["TSLA"])
result = strategy.backtest()
result.trades
Backtesting: 2018-01-01 00:00:00 to 2023-01-01 00:00:00
Loaded cached bar data.
Test split: 2018-01-02 00:00:00 to 2022-12-30 00:00:00
100% (1259 of 1259) |####################| Elapsed Time: 0:00:00 Time: 0:00:00
Finished backtest: 0:00:00
[3]:
| type | symbol | entry_date | exit_date | entry | exit | shares | pnl | return_pct | agg_pnl | bars | pnl_per_bar | stop | mae | mfe | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| id | |||||||||||||||
| 1 | long | TSLA | 2018-01-03 | 2018-01-22 | 21.36 | 23.50 | 4679 | 9994.34 | 10.0 | 9994.34 | 12 | 832.86 | profit | -0.98 | 2.14 |
| 2 | long | TSLA | 2018-01-23 | 2018-03-27 | 23.72 | 18.98 | 4637 | -21997.93 | -20.0 | -12003.58 | 44 | -499.95 | loss | -4.74 | 0.31 |
| 3 | long | TSLA | 2018-03-28 | 2018-04-04 | 17.36 | 19.10 | 4727 | 8206.07 | 10.0 | -3797.51 | 4 | 2051.52 | profit | -1.05 | 1.74 |
| 4 | long | TSLA | 2018-04-05 | 2018-06-07 | 19.82 | 21.80 | 4853 | 9618.65 | 10.0 | 5821.13 | 44 | 218.61 | profit | -1.59 | 1.98 |
| 5 | long | TSLA | 2018-06-08 | 2018-06-12 | 21.39 | 23.53 | 4947 | 10581.63 | 10.0 | 16402.77 | 2 | 5290.82 | profit | -0.25 | 2.14 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 85 | long | TSLA | 2022-07-29 | 2022-10-07 | 288.71 | 230.97 | 1010 | -58319.42 | -20.0 | 133548.98 | 49 | -1190.19 | loss | -57.74 | 25.96 |
| 86 | long | TSLA | 2022-10-10 | 2022-11-09 | 222.68 | 178.14 | 1046 | -46584.66 | -20.0 | 86964.32 | 22 | -2117.48 | loss | -44.54 | 14.72 |
| 87 | long | TSLA | 2022-11-10 | 2022-12-19 | 185.51 | 148.41 | 1007 | -37361.71 | -20.0 | 49602.61 | 26 | -1436.99 | loss | -37.10 | 15.31 |
| 88 | long | TSLA | 2022-12-20 | 2022-12-27 | 143.07 | 114.46 | 998 | -28556.77 | -20.0 | 21045.84 | 4 | -7139.19 | loss | -28.61 | 5.40 |
| 89 | long | TSLA | 2022-12-28 | 2022-12-29 | 112.25 | 123.48 | 1078 | 12100.55 | 10.0 | 33146.39 | 1 | 12100.55 | profit | -4.01 | 11.23 |
89 rows × 15 columns
移动止损
移动止损单会在证券价格跌破最高市场价格达到指定百分比或现金金额时自动退出交易。以下示例展示了在最高市场价格下跌 20% 处设置移动止损:
[4]:
def buy_with_trailing_stop_loss_and_profit(ctx):
if not ctx.long_pos():
ctx.buy_shares = ctx.calc_target_shares(1)
ctx.stop_trailing_pct = 20
ctx.stop_profit_pct = 10
strategy.clear_executions()
strategy.add_execution(buy_with_trailing_stop_loss_and_profit, ["TSLA"])
result = strategy.backtest()
result.trades
Backtesting: 2018-01-01 00:00:00 to 2023-01-01 00:00:00
Loaded cached bar data.
Test split: 2018-01-02 00:00:00 to 2022-12-30 00:00:00
100% (1259 of 1259) |####################| Elapsed Time: 0:00:00 Time: 0:00:00
Finished backtest: 0:00:00
[4]:
| type | symbol | entry_date | exit_date | entry | exit | shares | pnl | return_pct | agg_pnl | bars | pnl_per_bar | stop | mae | mfe | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| id | |||||||||||||||
| 1 | long | TSLA | 2018-01-03 | 2018-01-22 | 21.36 | 23.50 | 4679 | 9994.34 | 10.00 | 9994.34 | 12 | 832.86 | profit | -0.98 | 2.14 |
| 2 | long | TSLA | 2018-01-23 | 2018-03-27 | 23.72 | 19.20 | 4637 | -20959.24 | -19.06 | -10964.90 | 44 | -476.35 | trailing | -4.52 | 0.31 |
| 3 | long | TSLA | 2018-03-28 | 2018-04-04 | 17.36 | 19.10 | 4783 | 8303.29 | 10.00 | -2661.61 | 4 | 2075.82 | profit | -1.05 | 1.74 |
| 4 | long | TSLA | 2018-04-05 | 2018-06-07 | 19.82 | 21.80 | 4911 | 9733.60 | 10.00 | 7071.99 | 44 | 221.22 | profit | -1.59 | 1.98 |
| 5 | long | TSLA | 2018-06-08 | 2018-06-12 | 21.39 | 23.53 | 5005 | 10705.70 | 10.00 | 17777.69 | 2 | 5352.85 | profit | -0.25 | 2.14 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 102 | long | TSLA | 2022-08-02 | 2022-10-03 | 300.25 | 251.74 | 1095 | -53122.83 | -16.16 | 175831.91 | 43 | -1235.41 | trailing | -48.51 | 14.42 |
| 103 | long | TSLA | 2022-10-04 | 2022-10-24 | 249.75 | 199.80 | 1104 | -55144.80 | -20.00 | 120687.11 | 14 | -3938.91 | trailing | -49.95 | 7.75 |
| 104 | long | TSLA | 2022-10-25 | 2022-11-08 | 217.18 | 189.92 | 1016 | -27696.16 | -12.55 | 92990.95 | 10 | -2769.62 | trailing | -27.26 | 20.22 |
| 105 | long | TSLA | 2022-11-09 | 2022-12-13 | 186.50 | 160.66 | 1008 | -26050.75 | -13.86 | 66940.19 | 23 | -1132.64 | trailing | -25.84 | 14.32 |
| 106 | long | TSLA | 2022-12-14 | 2022-12-22 | 158.46 | 128.79 | 1037 | -30765.72 | -18.72 | 36174.48 | 6 | -5127.62 | trailing | -29.67 | 3.16 |
106 rows × 15 columns
设定限价
止损单可以与限价结合使用,以确保订单仅在特定价格水平执行。下面是在止损单上设置限价的示例:
[5]:
def buy_with_trailing_stop_loss_and_profit(ctx):
if not ctx.long_pos():
ctx.buy_shares = ctx.calc_target_shares(1)
ctx.stop_trailing_pct = 20
ctx.stop_trailing_limit = ctx.close[-1] + 1
ctx.stop_profit_pct = 10
ctx.stop_profit_limit = ctx.close[-1] - 1
strategy.clear_executions()
strategy.add_execution(buy_with_trailing_stop_loss_and_profit, ["TSLA"])
result = strategy.backtest()
result.trades.head()
Backtesting: 2018-01-01 00:00:00 to 2023-01-01 00:00:00
Loaded cached bar data.
Test split: 2018-01-02 00:00:00 to 2022-12-30 00:00:00
100% (1259 of 1259) |####################| Elapsed Time: 0:00:00 Time: 0:00:00
Finished backtest: 0:00:00
[5]:
| type | symbol | entry_date | exit_date | entry | exit | shares | pnl | return_pct | agg_pnl | bars | pnl_per_bar | stop | mae | mfe | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| id | |||||||||||||||
| 1 | long | TSLA | 2018-01-03 | 2018-01-22 | 21.36 | 23.50 | 4679 | 9994.34 | 10.0 | 9994.34 | 12 | 832.86 | profit | -0.98 | 2.14 |
| 2 | long | TSLA | 2018-01-23 | 2019-12-18 | 23.72 | 26.09 | 4637 | 10998.96 | 10.0 | 20993.31 | 480 | 22.91 | profit | -11.92 | 2.37 |
| 3 | long | TSLA | 2019-12-19 | 2020-01-03 | 26.78 | 29.46 | 4518 | 12099.20 | 10.0 | 33092.51 | 9 | 1344.36 | profit | -0.35 | 2.68 |
| 4 | long | TSLA | 2020-01-06 | 2020-01-08 | 29.72 | 32.69 | 4478 | 13308.62 | 10.0 | 46401.13 | 2 | 6654.31 | profit | -0.39 | 2.97 |
| 5 | long | TSLA | 2020-01-09 | 2020-01-14 | 32.39 | 35.63 | 4462 | 14452.42 | 10.0 | 60853.55 | 3 | 4817.47 | profit | -0.87 | 3.24 |
取消止损
以下代码展示了取消止损单的示例:
[6]:
def buy_with_stop_trailing_and_cancel(ctx):
pos = ctx.long_pos()
if not pos:
ctx.buy_shares = ctx.calc_target_shares(1)
ctx.stop_trailing_pct = 20
elif pos.bars > 60:
ctx.cancel_stops(ctx.symbol)
strategy.clear_executions()
strategy.add_execution(buy_with_stop_trailing_and_cancel, ["TSLA"])
result = strategy.backtest()
result.trades
Backtesting: 2018-01-01 00:00:00 to 2023-01-01 00:00:00
Loaded cached bar data.
Test split: 2018-01-02 00:00:00 to 2022-12-30 00:00:00
100% (1259 of 1259) |####################| Elapsed Time: 0:00:00 Time: 0:00:00
Finished backtest: 0:00:00
[6]:
| type | symbol | entry_date | exit_date | entry | exit | shares | pnl | return_pct | agg_pnl | bars | pnl_per_bar | stop | mae | mfe | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| id | |||||||||||||||
| 1 | long | TSLA | 2018-01-03 | 2018-03-27 | 21.36 | 19.22 | 4679 | -9994.34 | -10.0 | -9994.34 | 57 | -175.34 | trailing | -2.14 | 2.67 |
设置止损退出价格
默认情况下,PyBroker 会根据 K 线的最低价和最高价检查止损,并在止损触发的同一根 K 线上按止损的阈值(例如 -2%)退出交易。
要设置自定义退出价格,可以使用每种止损类型提供的 exit_price 字段。配置后,PyBroker 会根据 exit_price 检查止损,并在触发时使用该价格退出。以下代码将 stop_trailing_exit_price 设置为触发止损的 K 线的开盘价:
[7]:
from pybroker import PriceType
def buy_with_stop_trailing_and_exit_price(ctx):
if not ctx.long_pos():
ctx.buy_shares = ctx.calc_target_shares(1)
ctx.stop_trailing_pct = 20
ctx.stop_trailing_exit_price = PriceType.OPEN
strategy.clear_executions()
strategy.add_execution(buy_with_stop_trailing_and_exit_price, ["TSLA"])
result = strategy.backtest()
result.trades.head()
Backtesting: 2018-01-01 00:00:00 to 2023-01-01 00:00:00
Loaded cached bar data.
Test split: 2018-01-02 00:00:00 to 2022-12-30 00:00:00
100% (1259 of 1259) |####################| Elapsed Time: 0:00:00 Time: 0:00:00
Finished backtest: 0:00:00
[7]:
| type | symbol | entry_date | exit_date | entry | exit | shares | pnl | return_pct | agg_pnl | bars | pnl_per_bar | stop | mae | mfe | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| id | |||||||||||||||
| 1 | long | TSLA | 2018-01-03 | 2018-03-28 | 21.36 | 17.64 | 4679 | -17405.88 | -17.42 | -17405.88 | 58 | -300.10 | trailing | -3.72 | 2.67 |
| 2 | long | TSLA | 2018-03-29 | 2018-07-25 | 17.31 | 19.78 | 4771 | 11784.37 | 14.27 | -5621.51 | 81 | 145.49 | trailing | -1.00 | 7.61 |
| 3 | long | TSLA | 2018-07-26 | 2018-08-20 | 20.48 | 19.45 | 4585 | -4722.55 | -5.03 | -10344.06 | 17 | -277.80 | trailing | -1.40 | 5.35 |
| 4 | long | TSLA | 2018-08-21 | 2018-09-07 | 21.13 | 17.34 | 4243 | -16080.97 | -17.94 | -26425.03 | 12 | -1340.08 | trailing | -3.79 | 0.69 |
| 5 | long | TSLA | 2018-09-10 | 2018-12-26 | 18.57 | 20.00 | 3962 | 5665.66 | 7.70 | -20759.37 | 74 | 76.56 | trailing | -2.05 | 6.73 |
有关配置止损可用属性的更多详情,请参阅 ExecContext 参考文档。