Backtrader 文档学习-Quickstart

Backtrader 文档学习-Quickstart

0. 前言

backtrader,功能十分完善,有完整的使用文档,安装相对简单(直接pip安装即可)。
优点是运行速度快,支持pandas的矢量运算;支持参数自动寻优运算,内置了talib股票分析技术指标库;支持多品种、多策略、多周期的回测和交易;支持pyflio、empyrica分析模块库、alphalens多因子分析模块库等;扩展灵活,可以集成TensorFlow、PyTorch和Keras等机器学习、神经网络分析模块。
缺点:backtrader学习起来相对复杂,编程过程中使用了大量的元编程(类class),如果Python编程基础不扎实(尤其是类的操作),学习困难。另外一点,BackTrader不更新。(更正一下,GitHub上是更新的,2023-04-19 更新的最新版本1.9.78.123
在这里插入图片描述

如果将backtrader包分解为核心组件,主要包括以下组成部分:

  • (1)数据加载(Data Feed):将交易策略的数据加载到回测框架中。
  • (2)交易策略(Strategy):该模块是编程过程中最复杂的部分,需要设计交易决策,得出买入/卖出信号。
  • (3)回测框架设置( Cerebro):
    需要设置:(i)初始资金(ii)佣金(iii)数据馈送(iv)交易策略(v)交易头寸大小。
  • (4)运行回测:运行Cerebro回测并打印出所有已执行的交易。
  • (5)评估性能(Analyzers):以图形和风险收益等指标对交易策略的回测结果进行评价。

官网说明资料详细,有演示用例,逐步跟着一步步学习。

Backtrader 官网文档

1. 两个基本概念

(1)Lines

“Lines”是backtrader回测的数据,由一系列的点组成,通常包括以下类别的数据:Open(开盘价), High(最高价), Low(最低价), Close(收盘价), Volume(成交量), OpenInterest(无的话设置为0)。Data Feeds(数据加载)、Indicators(技术指标)和Strategies(策略)都会生成 Lines。
价格数据中的所有”Open” (开盘价)按时间组成一条 Line。所以,一组含有以上6个类别的价格数据,共有6条 Lines。如果算上“DateTime”(时间,可以看作是一组数据的主键),一共有7条 Lines。当访问一条 Line 的数据时,会默认指向下标为 0 的数据。最后一个数据通过下标 -1 来访问,在-1之后是索引0,用于访问当前时刻。因此,在回测过程中,无需知道已经处理了多少条/分钟/天/月,”0”一直指向当前值,下标 -1 来访问最后一个值。
Lines包括一个或多个line,line是一系列的数据,在图中可以形成一条线(line),有6个列数据,就是股票的主要数据集,最后一列没有用。

Open, High, Low, Close, Volume, OpenInterest

包括索引列“DateTime”,日期时间类型,注意:Datetime类型,不是Date类型。

(2)Index 0 Approach

访问行中的值时,将使用索引0访问当前值;
“最后一个”输出值是用索引**-1**访问,index-1用于访问可迭代项/数组的“最后”项。

在Backtrader中提供了1个函数来度量已处理数据bar的长度:
len:返回当前系统已经处理的数据(bars)。这个和python标准的len定义差异。

(3)版本

通过 pip index versions backtrader 检查版本。
版本:backtrader (1.9.78.123)

pip index  versions backtrader
WARNING: pip index is currently an experimental command. It may be removed/changed in a future release without prior warning.
backtrader (1.9.78.123)
Available versions: 1.9.78.123, 1.9.77.123, 1.9.76.123, 1.9.75.123, 1.9.74.123

2. 基本使用

(1)初始设置现金
cerebro.broker.setcash(100000.0)
from __future__ import (absolute_import, division, print_function,unicode_literals)import backtrader as btif __name__ == '__main__':cerebro = bt.Cerebro()cerebro.broker.setcash(100000.0)print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())cerebro.run()print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

因为没有任何策略,所以金额没有变化:

Starting Portfolio Value: 100000.00
Final Portfolio Value: 100000.00
(2)加载数据

示例使用的是Oracle的记录,实际使用,调整到国内数据。

from __future__ import (absolute_import, division, print_function,unicode_literals)import datetime  # For datetime objects
import os.path  # To manage paths
import sys  # To find out the script name (in argv[0])# Import the backtrader platform
import backtrader as btif __name__ == '__main__':# Create a cerebro entitycerebro = bt.Cerebro()# Datas are in a subfolder of the samples. Need to find where the script is# because it could have been called from anywheremodpath = os.path.dirname(os.path.abspath(sys.argv[0]))datapath = os.path.join(modpath, '../../datas/orcl-1995-2014.txt')# Create a Data Feeddata = bt.feeds.YahooFinanceCSVData(dataname=datapath,# Do not pass values before this datefromdate=datetime.datetime(2000, 1, 1),# Do not pass values after this datetodate=datetime.datetime(2000, 12, 31),reverse=False)# Add the Data Feed to Cerebrocerebro.adddata(data)# Set our desired cash startcerebro.broker.setcash(100000.0)# Print out the starting conditionsprint('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())# Run over everythingcerebro.run()# Print out the final resultprint('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

编写一个从数据库中取数据的函数使用:
注意:数据库中交易日期是date ,backtrader的数据集要求是datetime ,必须做好转换才能载入数据。

from sqlalchemy import create_engine
def get_code (stock_code):engine_ts = create_engine(connect parameter) # 执行sql操作sql = "select * from ts_stock t where t.stock_code=" + stock_code + ";"#stock_data = pd.read_sql(sql, con=engine_ts,index_col="date")  #因为BackTrader日期类型必须是datetime ,从数据库中读取的日期类型是date 。# 读数据,先不设置索引stock_data = pd.read_sql(sql, con=engine_ts) # ,index_col="date"# 增加一列,select 字段名是date,赋值到trade_date,同时转datetime类型stock_data['trade_date'] = pd.to_datetime(stock_data['date'], format='%Y%m%d %H:%M:%S')# 删除原来的date列stock_data.drop(columns=['date'])# 新datetime列作为索引列stock_data.set_index(['trade_date'], inplace=True)# 索引列改名stock_data.index.name='date'# 按backtrader 格式要求,第7列openinterest ,也可以不用# stock_data['openinterest'] = 0data = stock_data.sort_index(ascending=True)engine_ts.dispose()return(data)if __name__ == '__main__':# Create a cerebro entitycerebro = bt.Cerebro()stock_hfq_df = get_code('000858') #起止时间start_date = datetime.datetime(2015, 1, 1)  # 回测开始时间end_date = datetime.datetime(2019, 12, 31)  # 回测结束时间data = bt.feeds.PandasData(dataname=stock_hfq_df, fromdate=start_date, todate=end_date)  # 加载数据# Add the Data Feed to Cerebrocerebro.adddata(data)# Add the Data Feed to Cerebrocerebro.adddata(data)# Set our desired cash startcerebro.broker.setcash(100000.0)# Print out the starting conditionsprint('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())# Run over everythingcerebro.run()# Print out the final resultprint('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())    
(3)第一个策略 买入

在init方法中,可以使用载入的数据集,第一个数据是列表 self.datas[0] ,最后一个是 self.datas[-1] 。
self.dataclose=self.datas[0]。赋值close的引用,以后只需要一个间接引用dataclose ,就可以访问收盘值。
策略next方法将在系统时钟的每个bar上调用(self.datas[0]),直到符合策略条件,比如指标值设置,才能开始产生输出。
策略:
连续下跌三天,开始买入。
策略实施在next()方法中。

## 3.第一个策略
from __future__ import (absolute_import, division, print_function,unicode_literals)import datetime  # For datetime objects
import os.path  # To manage paths
import sys  # To find out the script name (in argv[0])# Import the backtrader platform
import backtrader as bt# Create a Stratey
class TestStrategy(bt.Strategy):def log(self, txt, dt=None):''' Logging function for this strategy'''dt = dt or self.datas[0].datetime.date(0)print('%s, %s' % (dt.isoformat(), txt))def __init__(self):# Keep a reference to the "close" line in the data[0] dataseriesself.dataclose = self.datas[0].closedef next(self):# Simply log the closing price of the series from the referenceself.log('Close, %.2f' % self.dataclose[0])if __name__ == '__main__':# Create a cerebro entity# delete log filelog_file = './bt_log.txt'delete_file(log_file)cerebro = bt.Cerebro()# Add a strategycerebro.addstrategy(TestStrategy)# 五粮液测试stock_hfq_df = get_code('000858') start_date = datetime.datetime(2015, 1, 1)  # 回测开始时间end_date = datetime.datetime(2019, 12, 31)  # 回测结束时间data = bt.feeds.PandasData(dataname=stock_hfq_df, fromdate=start_date, todate=end_date)  # 加载数据# Add the Data Feed to Cerebrocerebro.adddata(data)# Set our desired cash startcerebro.broker.setcash(100000.0)# Print out the starting conditionsprint('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())# Run over everythingcerebro.run()# Print out the final resultprint('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

调整:
输出都是close数据,数据显示比较多,都放到log文件中。 日志路径:

log_file = ‘./bt_log.txt’

修改TestStrategy 中的log方法,日志写入文件,便于查询。后不赘述。

## 3.第一个策略
from __future__ import (absolute_import, division, print_function,unicode_literals)import datetime  # For datetime objects
import os.path  # To manage paths
import sys  # To find out the script name (in argv[0])# Import the backtrader platform
import backtrader as bt
import os# delete log file
def delete_file(filename):# if log file exist if os.path.exists(filename):os.remove(filename)# Create a Stratey
class TestStrategy(bt.Strategy):def log(self, txt, dt=None):''' Logging function for this strategy'''dt = dt or self.datas[0].datetime.date(0)#print('%s, %s' % (dt.isoformat(), txt))with open(log_file, 'a') as file:file.write('%s, %s' % (dt.isoformat(), txt))file.write('\n')def __init__(self):# Keep a reference to the "close" line in the data[0] dataseriesself.dataclose = self.datas[0].closedef next(self):# Simply log the closing price of the series from the referenceself.log('Close, %.2f' % self.dataclose[0])if __name__ == '__main__':# delete log filelog_file = './bt_log.txt'delete_file(log_file)# Create a cerebro entitycerebro = bt.Cerebro()# Add a strategycerebro.addstrategy(TestStrategy)stock_hfq_df = get_code('000858') start_date = datetime.datetime(2015, 1, 1)  # 回测开始时间end_date = datetime.datetime(2019, 12, 31)  # 回测结束时间data = bt.feeds.PandasData(dataname=stock_hfq_df, fromdate=start_date, todate=end_date)  # 加载数据# Add the Data Feed to Cerebrocerebro.adddata(data)# Set our desired cash startcerebro.broker.setcash(100000.0)# Print out the starting conditionsprint('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())# Run over everythingcerebro.run()# Print out the final resultprint('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

执行后,没有交易过程记录,都在日志文件中显示:

Starting Portfolio Value: 100000.00
Final Portfolio Value: 100000.00

再增加策略中的逻辑:
策略:连续三天下跌,开始买入操作

# Create a Stratey
class TestStrategy(bt.Strategy):def log(self, txt, dt=None):''' Logging function for this strategy'''dt = dt or self.datas[0].datetime.date(0)#print('%s, %s' % (dt.isoformat(), txt))with open(log_file, 'a') as file:file.write('%s, %s' % (dt.isoformat(), txt))file.write('\n')def __init__(self):# Keep a reference to the "close" line in the data[0] dataseriesself.dataclose = self.datas[0].close#Open, High, Low, Close, Volume, OpenInterestself.dataclose = self.datas[0].closeself.dataopen = self.datas[0].openself.datahigh = self.datas[0].highself.datalow = self.datas[0].lowself.datavol = self.datas[0].volumedef next(self):# Simply log the closing price of the series from the referenceself.log('Close, %.2f' % self.dataclose[0])if self.dataclose[0] < self.dataclose[-1]:# current close less than previous closeif self.dataclose[-1] < self.dataclose[-2]:# previous close less than the previous close# BUY, BUY, BUY!!! (with all possible default parameters)self.log('BUY CREATE, %.2f' % self.dataclose[0])self.buy()

说明:

  • self.datas[0] 就是购买的股票。
  • 默认购买单位是1,每次买1股 。position
    sizer属性来记录,缺省值为1,就是每一次操作只买卖1股。当前order订单执行的时候,采用的价格是触发购买条件第二天的开盘价。
2018-01-02, Close, 80.58
2018-01-03, Close, 80.90
2018-01-04, Close, 82.99
2018-01-05, Close, 82.68
2018-01-08, Close, 82.20
2018-01-08, BUY CREATE, 82.20
2018-01-09, Close, 86.10
2018-01-10, Close, 88.90

5号第一天下跌,8日第二天连续下跌,触发购买信号,购买价格就是8号的收盘价,就是9日的开盘价。

  • 当前order执行的时候,没有收佣金。佣金如何设置后续还会说明。

可以看Strategy类有什么方法、属性:

method = ""
for i in dir(bt.Strategy):if i[:1] != '_' :method += i + ','
print(method)   

方法和属性:

IndType,ObsType,PriceClose,PriceDateTime,PriceHigh,PriceLow,PriceOpen,PriceOpenInteres,PriceVolume,StratType,add_timer,addindicator,addminperiod,advance,alias,aliased,array,backwards,bind2line,bind2lines,bindlines,buy,buy_bracket,cancel,clear,close,csv,extend,forward,frompackages,getdatabyname,getdatanames,getindicators,getindicators_lines,getobservers,getposition,getpositionbyname,getpositions,getpositionsbyname,getsizer,getsizing,getwriterheaders,getwriterinfo,getwritervalues,home,incminperiod,linealias,lines,minbuffer,next,next_open,nextstart,nextstart_open,notify_cashvalue,notify_data,notify_fund,notify_order,notify_store,notify_timer,notify_trade,once,oncestart,order_target_percent,order_target_size,order_target_value,packages,params,plotinfo,plotlabel,plotlines,position,positionbyname,positions,positionsbyname,prenext,prenext_open,preonce,qbuffer,reset,rewind,sell,sell_bracket,set_tradehistory,setminperiod,setsizer,sizer,start,stop,updateminperiod,
(4)还要卖出
  • Strategy对象提供了对默认数据的位置属性的访问
  • 方法buy和sell 都创建(尚未执行)执行订单
  • Strategy订单状态的变化将通过notify 方法调用
  • 卖出策略是:持仓5天,在第6天卖出
# 4.不但买入,还要卖出# Create a Stratey
class TestStrategy(bt.Strategy):def log(self, txt, dt=None):''' Logging function for this strategy'''dt = dt or self.datas[0].datetime.date(0)#print('%s, %s' % (dt.isoformat(), txt))with open(log_file, 'a') as file:file.write('%s, %s' % (dt.isoformat(), txt))file.write('\n')def __init__(self):# Keep a reference to the "close" line in the data[0] dataseriesself.dataclose = self.datas[0].close#Open, High, Low, Close, Volume, OpenInterestself.dataclose = self.datas[0].closeself.dataopen = self.datas[0].openself.datahigh = self.datas[0].highself.datalow = self.datas[0].lowself.datavol = self.datas[0].volume# To keep track of pending ordersself.order = None                def notify_order(self, order):# 买卖订单的状态:提交和接受,通过broker控制    if order.status in [order.Submitted, order.Accepted]:# Buy/Sell order submitted/accepted to/by broker - Nothing to doreturn# Check if an order has been completed# Attention: broker could reject order if not enough cash# broker如果资金不足将reject订单#订单状态是完成if order.status in [order.Completed]:#判断是买单,写日志if order.isbuy():self.log('BUY EXECUTED, %.2f' % order.executed.price)#判读是卖单,写日志elif order.issell():self.log('SELL EXECUTED, %.2f' % order.executed.price)#定义bar_executed 变量,记录处理bar的数量#len:返回当前系统已经处理的数据(bars)。这个和python标准的len定义差异。self.bar_executed = len(self)self.bar_buffer =  lenbuf(self)elif order.status in [order.Canceled, order.Margin, order.Rejected]:self.log('Order Canceled/Margin/Rejected')# Write down: no pending orderself.order = Nonedef next(self):# Simply log the closing price of the series from the referenceself.log('Close, %.2f' % self.dataclose[0])# Check if an order is pending ... if yes, we cannot send a 2nd oneif self.order:return# Check if we are in the marketif not self.position:# Not yet ... we MIGHT BUY if ...#连续两天下跌,开始买入if self.dataclose[0] < self.dataclose[-1]:# current close less than previous closeif self.dataclose[-1] < self.dataclose[-2]:# previous close less than the previous close# BUY, BUY, BUY!!! (with default parameters)self.log('BUY CREATE, %.2f' % self.dataclose[0])# Keep track of the created order to avoid a 2nd orderself.order = self.buy()else:# Already in the market ... we might sellif len(self) >= (self.bar_executed + 5):# SELL, SELL, SELL!!! (with all possible default parameters)self.log('SELL CREATE, %.2f' % self.dataclose[0])# Keep track of the created order to avoid a 2nd orderself.order = self.sell()if __name__ == '__main__':# delete log filelog_file = './bt_log.txt'delete_file(log_file)# Create a cerebro entitycerebro = bt.Cerebro()# Add a strategycerebro.addstrategy(TestStrategy)stock_hfq_df = get_code('000858') start_date = datetime.datetime(2015, 1, 1)  # 回测开始时间end_date = datetime.datetime(2019, 12, 31)  # 回测结束时间data = bt.feeds.PandasData(dataname=stock_hfq_df, fromdate=start_date, todate=end_date)  # 加载数据# Add the Data Feed to Cerebrocerebro.adddata(data)# Set our desired cash startcerebro.broker.setcash(100000.0)# Print out the starting conditionsprint('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())# Run over everythingcerebro.run()# Print out the final resultprint('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

执行流程,每次买卖数量都是1股:
5日下跌,6日下跌,创建买单,9日执行买单,是9日的开盘价。
买单时,处理的是6个bar 。
从10日开始,到16日是持仓第5天,创建卖单,17日,开盘卖出。
执行结果:

2018-01-02, Close, 80.58
2018-01-03, Close, 80.90
2018-01-04, Close, 82.99
2018-01-05, Close, 82.68
2018-01-08, Close, 82.20
2018-01-08, BUY CREATE, 82.20
2018-01-09, BUY EXECUTED, 82.40
2018-01-09, Bar executed :6
2018-01-09, Close, 86.10
2018-01-10, Close, 88.90
2018-01-11, Close, 87.96
2018-01-12, Close, 91.37
2018-01-15, Close, 91.75
2018-01-16, Close, 90.82
2018-01-16, SELL CREATE, 90.82
2018-01-17, SELL EXECUTED, 90.30
2018-01-17, Bar executed :12
... ...
... ...
... ...

订单的状态是通过Order对象的status属性来表示的。status属性可以是以下几个值之一:

  • Order.Submitted:订单已提交,但尚未成交。
  • Order.Accepted:订单已被接受,正在等待成交。
  • Order.Completed:订单已完全成交。
  • Order.Canceled:订单已取消。
  • Order.Margin:订单由于保证金不足而被拒绝。
  • Order.Rejected:订单被拒绝,原因可能是无效的价格、数量等。
(5)考虑券商佣金

在main函数中增加

    # Set the commission - 0.1% ... divide by 100 to remove the %cerebro.broker.setcommission(commission=0.001)

修改后的策略:
增加 方法 def notify_trade(self, trade):
用于计算毛利和纯利 ,通过trade对象计算。
查看在backtrader 目录下的trade.py源码:
定义属性:
pnl定义毛利,pnlcomm定义毛利-佣金

Attributes:- ``status`` (``dict`` with '.' notation): Holds the resulting status ofan update event and has the following sub-attributes- ``status`` (``int``): Trade status- ``dt`` (``float``): float coded datetime- ``barlen`` (``int``): number of bars the trade has been active- ``size`` (``int``): current size of the Trade- ``price`` (``float``): current price of the Trade- ``value`` (``float``): current monetary value of the Trade- ``pnl`` (``float``): current profit and loss of the Trade- ``pnlcomm`` (``float``): current profit and loss minus commission- ``event`` (``dict`` with '.' notation): Holds the event update- parameters- ``order`` (``object``): the order which initiated the``update``- ``size`` (``int``): size of the update- ``price`` (``float``):price of the update- ``commission`` (``float``): price of the update'''
#5. 考虑佣金
# Create a Stratey
class TestStrategy(bt.Strategy):def log(self, txt, dt=None):''' Logging function for this strategy'''dt = dt or self.datas[0].datetime.date(0)#print('%s, %s' % (dt.isoformat(), txt))with open(log_file, 'a') as file:file.write('%s, %s' % (dt.isoformat(), txt))file.write('\n')def __init__(self):# Keep a reference to the "close" line in the data[0] dataseriesself.dataclose = self.datas[0].close#Open, High, Low, Close, Volume, OpenInterestself.dataclose = self.datas[0].closeself.dataopen = self.datas[0].openself.datahigh = self.datas[0].highself.datalow = self.datas[0].lowself.datavol = self.datas[0].volume# To keep track of pending ordersself.order = None                # To keep track of pending orders and buy price/commissionself.order = Noneself.buyprice = Noneself.buycomm = None# 统计毛利和净利润self.gross = 0.0self.net = 0.0def notify_order(self, order):# 买卖订单的状态:提交和接受,通过broker控制    if order.status in [order.Submitted, order.Accepted]:# Buy/Sell order submitted/accepted to/by broker - Nothing to doreturn# Check if an order has been completed# Attention: broker could reject order if not enough cash# broker如果资金不足将reject订单#订单状态是完成if order.status in [order.Completed]:#判断是买单,写日志if order.isbuy():self.log('BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,order.executed.comm))self.buyprice = order.executed.priceself.buycomm = order.executed.comm#判读是卖单,写日志elif order.issell():self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,order.executed.comm))#定义bar_executed 变量,记录处理bar的数量#len:返回当前系统已经处理的数据(bars)。这个和python标准的len定义差异。self.bar_executed = len(self)#日志显示处理的bar数量,逐渐递增。strlog = 'Bar executed :' + str(self.bar_executed)self.log(strlog)# 订单取消、保证金不足、退回elif order.status in [order.Canceled, order.Margin, order.Rejected]:self.log('Order Canceled/Margin/Rejected')# Write down: no pending order# 处理完订单,无挂起订单,重置订单为空self.order = Nonedef notify_trade(self, trade):# 如果不是平仓,返回if not trade.isclosed:return# 平仓计算成本和利润self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %(trade.pnl, trade.pnlcomm))# 累计毛利和净利润self.gross += trade.pnlself.net =+ trade.pnlcommself.log ('Accumulated profit,GROSS  %.2f, NET %.2f' % (self.gross,self.net))def next(self):# Simply log the closing price of the series from the referenceself.log('Close, %.2f' % self.dataclose[0])# Check if an order is pending ... if yes, we cannot send a 2nd oneif self.order:return# Check if we are in the marketif not self.position:# Not yet ... we MIGHT BUY if ...#连续两天下跌,开始买入if self.dataclose[0] < self.dataclose[-1]:# current close less than previous closeif self.dataclose[-1] < self.dataclose[-2]:# previous close less than the previous close# BUY, BUY, BUY!!! (with default parameters)self.log('BUY CREATE, %.2f' % self.dataclose[0])# Keep track of the created order to avoid a 2nd orderself.order = self.buy()else:# Already in the market ... we might sell# 持仓5天if len(self) >= (self.bar_executed + 5):# SELL, SELL, SELL!!! (with all possible default parameters)self.log('SELL CREATE, %.2f' % self.dataclose[0])# Keep track of the created order to avoid a 2nd orderself.order = self.sell()

执行结果:

Starting Portfolio Value: 100000.00
Final Portfolio Value: 100040.35

日志内容:

2018-01-02, Close, 80.58
2018-01-03, Close, 80.90
2018-01-04, Close, 82.99
2018-01-05, Close, 82.68
2018-01-08, Close, 82.20
2018-01-08, BUY CREATE, 82.20
2018-01-09, BUY EXECUTED, Price: 82.40, Cost: 82.40, Comm 0.01
2018-01-09, Bar executed :6
2018-01-09, Close, 86.10
2018-01-10, Close, 88.90
2018-01-11, Close, 87.96
2018-01-12, Close, 91.37
2018-01-15, Close, 91.75
2018-01-16, Close, 90.82
2018-01-16, SELL CREATE, 90.82
2018-01-17, SELL EXECUTED, Price: 90.30, Cost: 82.40, Comm 0.01
2018-01-17, Bar executed :12
2018-01-17, OPERATION PROFIT, GROSS 7.90, NET 7.88
2018-01-17, Accumulated profit,GROSS  7.90, NET 7.88
2018-01-17, Close, 86.01
... ... 
... ... 
2019-12-12, BUY CREATE, 127.78
2019-12-13, BUY EXECUTED, Price: 128.58, Cost: 128.58, Comm 0.01
2019-12-13, Bar executed :475
2019-12-13, Close, 129.52
2019-12-16, Close, 128.83
2019-12-17, Close, 130.25
2019-12-18, Close, 130.94
2019-12-19, Close, 129.86
2019-12-20, Close, 129.10
2019-12-20, SELL CREATE, 129.10
2019-12-23, SELL EXECUTED, Price: 127.50, Cost: 128.58, Comm 0.01
2019-12-23, Bar executed :481
2019-12-23, OPERATION PROFIT, GROSS -1.08, NET -1.11
2019-12-23, Accumulated profit,GROSS  36.59, NET -1.11
2019-12-23, Close, 128.14
2019-12-23, BUY CREATE, 128.14
2019-12-24, BUY EXECUTED, Price: 128.44, Cost: 128.44, Comm 0.01
2019-12-24, Bar executed :482
2019-12-24, Close, 128.70
2019-12-25, Close, 128.10
2019-12-26, Close, 128.15
2019-12-27, Close, 129.00
2019-12-30, Close, 132.82
2019-12-31, Close, 133.01
2019-12-31, SELL CREATE, 133.01

可以看出

2018-01-17, SELL EXECUTED, Price: 90.30, Cost: 82.40, Comm 0.01

盈利:90.30 - 82.40 = 7.90元,佣金0.01

2018-01-17, OPERATION PROFIT, GROSS 7.90, NET 7.88

毛利:7.90元 ,买卖两次,佣金0.02
净利润:7.90 - 0.02 = 7.88 元

(6)优化策略参数

在main函数中增加,每次购买10股,默认是1股。

# Add a FixedSize sizer according to the stake
cerebro.addsizer(bt.sizers.FixedSize, stake=10)

在TestStrategy(bt.Strategy) 类定义中,增加参数。

params = (('exitbars', 5),
)

用于持仓天数,默认是5天。
修改后代码:

#6. 优化参数
# Create a Stratey
class TestStrategy(bt.Strategy):params = (('exitbars', 5),)def log(self, txt, dt=None):''' Logging function for this strategy'''dt = dt or self.datas[0].datetime.date(0)#print('%s, %s' % (dt.isoformat(), txt))with open(log_file, 'a') as file:file.write('%s, %s' % (dt.isoformat(), txt))file.write('\n')def __init__(self):# Keep a reference to the "close" line in the data[0] dataseriesself.dataclose = self.datas[0].close#Open, High, Low, Close, Volume, OpenInterestself.dataclose = self.datas[0].closeself.dataopen = self.datas[0].openself.datahigh = self.datas[0].highself.datalow = self.datas[0].lowself.datavol = self.datas[0].volume# To keep track of pending ordersself.order = None                # To keep track of pending orders and buy price/commissionself.order = Noneself.buyprice = Noneself.buycomm = None# 统计毛利和净利润self.gross = 0.0self.net = 0.0def notify_order(self, order):# 买卖订单的状态:提交和接受,通过broker控制    if order.status in [order.Submitted, order.Accepted]:# Buy/Sell order submitted/accepted to/by broker - Nothing to doreturn# Check if an order has been completed# Attention: broker could reject order if not enough cash# broker如果资金不足将reject订单#订单状态是完成if order.status in [order.Completed]:#判断是买单,写日志if order.isbuy():self.log('BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,order.executed.comm))self.buyprice = order.executed.priceself.buycomm = order.executed.comm#判读是卖单,写日志elif order.issell():self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,order.executed.comm))#定义bar_executed 变量,记录处理bar的数量#len:返回当前系统已经处理的数据(bars)。这个和python标准的len定义差异。self.bar_executed = len(self)#日志显示处理的bar数量,逐渐递增。strlog = 'Bar executed :' + str(self.bar_executed)self.log(strlog)# 订单取消、保证金不足、退回elif order.status in [order.Canceled, order.Margin, order.Rejected]:self.log('Order Canceled/Margin/Rejected')# Write down: no pending order# 处理完订单,无挂起订单,重置订单为空self.order = Nonedef notify_trade(self, trade):# 如果不是平仓,返回if not trade.isclosed:return# 平仓计算成本和利润self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %(trade.pnl, trade.pnlcomm))# 累计毛利和净利润self.gross += trade.pnlself.net =+ trade.pnlcommself.log ('Accumulated profit,GROSS  %.2f, NET %.2f' % (self.gross,self.net))def next(self):# Simply log the closing price of the series from the referenceself.log('Close, %.2f' % self.dataclose[0])# Check if an order is pending ... if yes, we cannot send a 2nd oneif self.order:return# Check if we are in the marketif not self.position:# Not yet ... we MIGHT BUY if ...#连续两天下跌,开始买入if self.dataclose[0] < self.dataclose[-1]:# current close less than previous closeif self.dataclose[-1] < self.dataclose[-2]:# previous close less than the previous close# BUY, BUY, BUY!!! (with default parameters)self.log('BUY CREATE, %.2f' % self.dataclose[0])# Keep track of the created order to avoid a 2nd orderself.order = self.buy()else:# Already in the market ... we might sell# 持仓5天if len(self) >= (self.bar_executed + self.params.exitbars):# SELL, SELL, SELL!!! (with all possible default parameters)self.log('SELL CREATE, %.2f' % self.dataclose[0])# Keep track of the created order to avoid a 2nd orderself.order = self.sell()if __name__ == '__main__':# delete log filelog_file = './bt_log.txt'delete_file(log_file)# Create a cerebro entitycerebro = bt.Cerebro()# Add a strategycerebro.addstrategy(TestStrategy)stock_hfq_df = get_code('111969') start_date = datetime.datetime(2015, 1, 1)  # 回测开始时间end_date = datetime.datetime(2019, 12, 31)  # 回测结束时间data = bt.feeds.PandasData(dataname=stock_hfq_df, fromdate=start_date, todate=end_date)  # 加载数据# Add the Data Feed to Cerebrocerebro.adddata(data)# Set our desired cash startcerebro.broker.setcash(100000.0)# Set the commission - 0.1% ... divide by 100 to remove the %# 按万一的佣金 ,买卖操作都要扣除cerebro.broker.setcommission(commission=0.0001)# Add a FixedSize sizer according to the stakecerebro.addsizer(bt.sizers.FixedSize, stake=10)# Print out the starting conditionsprint('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())# Run over everythingcerebro.run()# Print out the final resultprint('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

执行输出结果:

Starting Portfolio Value: 100000.00
Final Portfolio Value: 100403.51

由于每次购买10股,盈利增加。
日志:

2018-01-02, Close, 80.58
2018-01-03, Close, 80.90
2018-01-04, Close, 82.99
2018-01-05, Close, 82.68
2018-01-08, Close, 82.20
2018-01-08, BUY CREATE, 82.20
2018-01-09, BUY EXECUTED, Price: 82.40, Cost: 824.00, Comm 0.08
2018-01-09, Bar executed :6
2018-01-09, Close, 86.10
2018-01-10, Close, 88.90
2018-01-11, Close, 87.96
2018-01-12, Close, 91.37
2018-01-15, Close, 91.75
2018-01-16, Close, 90.82
2018-01-16, SELL CREATE, 90.82
2018-01-17, SELL EXECUTED, Price: 90.30, Cost: 824.00, Comm 0.09
2018-01-17, Bar executed :12
2018-01-17, OPERATION PROFIT, GROSS 79.00, NET 78.83
2018-01-17, Accumulated profit,GROSS  79.00, NET 78.83
2018-01-17, Close, 86.01

一次买卖,平仓后,净利润和毛利都增加。

(7)增加指示器indicator

上面的例子,买入是连跌三天,卖出是持仓5天。策略简单粗暴。
通过indicator的均线,做买入卖出指标,更加合理一点。

  • 如果收盘价高于平均值,则买入
  • 如果收盘价小于平均值,则卖出
  • 只允许1个交易活动操作,买一单,卖出一单的模式

修改内容:

  • 策略增加参数,SMA周期参数,默认设置30日 。
params = (         ('maperiod', 30),('exitbars', 5),    )
  • 在next方法中,调整买卖的判断。
#7. 使用指示器
# Create a Stratey
class TestStrategy(bt.Strategy):params = (('maperiod', 30),('exitbars', 5),)def log(self, txt, dt=None):''' Logging function for this strategy'''dt = dt or self.datas[0].datetime.date(0)#print('%s, %s' % (dt.isoformat(), txt))with open(log_file, 'a') as file:file.write('%s, %s' % (dt.isoformat(), txt))file.write('\n')def __init__(self):# Keep a reference to the "close" line in the data[0] dataseriesself.dataclose = self.datas[0].close#Open, High, Low, Close, Volume, OpenInterestself.dataclose = self.datas[0].closeself.dataopen = self.datas[0].openself.datahigh = self.datas[0].highself.datalow = self.datas[0].lowself.datavol = self.datas[0].volume# To keep track of pending ordersself.order = None                # To keep track of pending orders and buy price/commissionself.order = Noneself.buyprice = Noneself.buycomm = None# 统计毛利和净利润self.gross = 0.0self.net = 0.0# Add a MovingAverageSimple indicator# 使用简单移动平均线确定买入和卖出操作self.sma = bt.indicators.SimpleMovingAverage(self.datas[0], period=self.params.maperiod)def notify_order(self, order):# 买卖订单的状态:提交和接受,通过broker控制    if order.status in [order.Submitted, order.Accepted]:# Buy/Sell order submitted/accepted to/by broker - Nothing to doreturn# Check if an order has been completed# Attention: broker could reject order if not enough cash# broker如果资金不足将reject订单#订单状态是完成if order.status in [order.Completed]:#判断是买单,写日志if order.isbuy():self.log('BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,order.executed.comm))self.buyprice = order.executed.priceself.buycomm = order.executed.comm#判读是卖单,写日志elif order.issell():self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,order.executed.comm))#定义bar_executed 变量,记录处理bar的数量#len:返回当前系统已经处理的数据(bars)。这个和python标准的len定义差异。self.bar_executed = len(self)#日志显示处理的bar数量,逐渐递增。strlog = 'Bar executed :' + str(self.bar_executed)self.log(strlog)# 订单取消、保证金不足、退回elif order.status in [order.Canceled, order.Margin, order.Rejected]:self.log('Order Canceled/Margin/Rejected')# Write down: no pending order# 处理完订单,无挂起订单,重置订单为空self.order = Nonedef notify_trade(self, trade):# 如果不是平仓,返回if not trade.isclosed:return# 平仓计算成本和利润self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %(trade.pnl, trade.pnlcomm))# 累计毛利和净利润self.gross += trade.pnlself.net =+ trade.pnlcommself.log ('Accumulated profit,GROSS  %.2f, NET %.2f' % (self.gross,self.net))def next(self):# Simply log the closing price of the series from the referenceself.log('Close, %.2f' % self.dataclose[0])# Check if an order is pending ... if yes, we cannot send a 2nd oneif self.order:return# Check if we are in the marketif not self.position:# Not yet ... we MIGHT BUY if ...#收盘穿过简单平均移动线,买入if self.dataclose[0] > self.sma[0]:# current close less than previous closeif self.dataclose[-1] < self.dataclose[-2]:# previous close less than the previous close# BUY, BUY, BUY!!! (with default parameters)self.log('BUY CREATE, %.2f' % self.dataclose[0])# Keep track of the created order to avoid a 2nd orderself.order = self.buy()else:# Already in the market ... we might sell#收盘穿过简单平均移动线,买入if self.dataclose[0] < self.sma[0]:# SELL, SELL, SELL!!! (with all possible default parameters)self.log('SELL CREATE, %.2f' % self.dataclose[0])# Keep track of the created order to avoid a 2nd orderself.order = self.sell()if __name__ == '__main__':# delete log filelog_file = './bt_log.txt'delete_file(log_file)# Create a cerebro entitycerebro = bt.Cerebro()# Add a strategycerebro.addstrategy(TestStrategy)stock_hfq_df = get_code('111969') start_date = datetime.datetime(2015, 1, 1)  # 回测开始时间end_date = datetime.datetime(2019, 12, 31)  # 回测结束时间data = bt.feeds.PandasData(dataname=stock_hfq_df, fromdate=start_date, todate=end_date)  # 加载数据# Add the Data Feed to Cerebrocerebro.adddata(data)# Set our desired cash startcerebro.broker.setcash(100000.0)# Set the commission - 0.1% ... divide by 100 to remove the %# 按万一的佣金 ,买卖操作都要扣除cerebro.broker.setcommission(commission=0.0001)# Add a FixedSize sizer according to the stakecerebro.addsizer(bt.sizers.FixedSize, stake=10)# Print out the starting conditionsprint('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())# Run over everythingcerebro.run()# Print out the final resultprint('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

执行结果:

Starting Portfolio Value: 100000.00
Final Portfolio Value: 100522.68

比简单判断下跌买入,持仓5天卖出的策略,收益高119.17。

Starting Portfolio Value: 100000.00
Final Portfolio Value: 100403.51
(8)可视化

内置的plot方法,参数如下:

def plot(self, plotter=None, numfigs=1, iplot=True, start=None, end=None,width=16, height=9, dpi=300, tight=True, use=None, **kwargs):

说明:如果在jupyter中直接绘图,报错

cerebro.plot() 

报错:Javascript Error: IPython is not defined
解决方法:
%matplotlib inline
调用绘图:

cerebro.plot(iplot=False)

在jupyter中可以绘图。

在init方法中增加绘图指示器指标:

        # Indicators for the plotting showbt.indicators.ExponentialMovingAverage(self.datas[0], period=25)bt.indicators.WeightedMovingAverage(self.datas[0], period=25,subplot=True)bt.indicators.StochasticSlow(self.datas[0])bt.indicators.MACDHisto(self.datas[0])rsi = bt.indicators.RSI(self.datas[0])bt.indicators.SmoothedMovingAverage(rsi, period=10)bt.indicators.ATR(self.datas[0], plot=False)
#8. 可视化
# Create a Stratey
class TestStrategy(bt.Strategy):params = (('maperiod', 30),('exitbars', 5),)def log(self, txt, dt=None):''' Logging function for this strategy'''dt = dt or self.datas[0].datetime.date(0)#print('%s, %s' % (dt.isoformat(), txt))with open(log_file, 'a') as file:file.write('%s, %s' % (dt.isoformat(), txt))file.write('\n')def __init__(self):# Keep a reference to the "close" line in the data[0] dataseriesself.dataclose = self.datas[0].close#Open, High, Low, Close, Volume, OpenInterestself.dataclose = self.datas[0].closeself.dataopen = self.datas[0].openself.datahigh = self.datas[0].highself.datalow = self.datas[0].lowself.datavol = self.datas[0].volume# To keep track of pending ordersself.order = None                # To keep track of pending orders and buy price/commissionself.order = Noneself.buyprice = Noneself.buycomm = None# 统计毛利和净利润self.gross = 0.0self.net = 0.0# Add a MovingAverageSimple indicator# 使用简单移动平均线确定买入和卖出操作self.sma = bt.indicators.SimpleMovingAverage(self.datas[0], period=self.params.maperiod)# Indicators for the plotting showbt.indicators.ExponentialMovingAverage(self.datas[0], period=25)bt.indicators.WeightedMovingAverage(self.datas[0], period=25,subplot=True)bt.indicators.StochasticSlow(self.datas[0])bt.indicators.MACDHisto(self.datas[0])rsi = bt.indicators.RSI(self.datas[0])bt.indicators.SmoothedMovingAverage(rsi, period=10)bt.indicators.ATR(self.datas[0], plot=False)def notify_order(self, order):# 买卖订单的状态:提交和接受,通过broker控制    if order.status in [order.Submitted, order.Accepted]:# Buy/Sell order submitted/accepted to/by broker - Nothing to doreturn# Check if an order has been completed# Attention: broker could reject order if not enough cash# broker如果资金不足将reject订单#订单状态是完成if order.status in [order.Completed]:#判断是买单,写日志if order.isbuy():self.log('BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,order.executed.comm))self.buyprice = order.executed.priceself.buycomm = order.executed.comm#判读是卖单,写日志elif order.issell():self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,order.executed.comm))#定义bar_executed 变量,记录处理bar的数量#len:返回当前系统已经处理的数据(bars)。这个和python标准的len定义差异。self.bar_executed = len(self)#日志显示处理的bar数量,逐渐递增。strlog = 'Bar executed :' + str(self.bar_executed)self.log(strlog)# 订单取消、保证金不足、退回elif order.status in [order.Canceled, order.Margin, order.Rejected]:self.log('Order Canceled/Margin/Rejected')# Write down: no pending order# 处理完订单,无挂起订单,重置订单为空self.order = Nonedef notify_trade(self, trade):# 如果不是平仓,返回if not trade.isclosed:return# 平仓计算成本和利润self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %(trade.pnl, trade.pnlcomm))# 累计毛利和净利润self.gross += trade.pnlself.net =+ trade.pnlcommself.log ('Accumulated profit,GROSS  %.2f, NET %.2f' % (self.gross,self.net))def next(self):# Simply log the closing price of the series from the referenceself.log('Close, %.2f' % self.dataclose[0])# Check if an order is pending ... if yes, we cannot send a 2nd oneif self.order:return# Check if we are in the marketif not self.position:# Not yet ... we MIGHT BUY if ...#收盘穿过简单平均移动线,买入if self.dataclose[0] > self.sma[0]:# current close less than previous closeif self.dataclose[-1] < self.dataclose[-2]:# previous close less than the previous close# BUY, BUY, BUY!!! (with default parameters)self.log('BUY CREATE, %.2f' % self.dataclose[0])# Keep track of the created order to avoid a 2nd orderself.order = self.buy()else:# Already in the market ... we might sell#收盘穿过简单平均移动线,买入if self.dataclose[0] < self.sma[0]:# SELL, SELL, SELL!!! (with all possible default parameters)self.log('SELL CREATE, %.2f' % self.dataclose[0])# Keep track of the created order to avoid a 2nd orderself.order = self.sell()%matplotlib inline
if __name__ == '__main__':# delete log filelog_file = './bt_log.txt'delete_file(log_file)# Create a cerebro entitycerebro = bt.Cerebro()# Add a strategycerebro.addstrategy(TestStrategy)stock_hfq_df = get_code('111969') start_date = datetime.datetime(2015, 1, 1)  # 回测开始时间end_date = datetime.datetime(2019, 12, 31)  # 回测结束时间data = bt.feeds.PandasData(dataname=stock_hfq_df, fromdate=start_date, todate=end_date)  # 加载数据# Add the Data Feed to Cerebrocerebro.adddata(data)# Set our desired cash startcerebro.broker.setcash(100000.0)# Set the commission - 0.1% ... divide by 100 to remove the %# 按万一的佣金 ,买卖操作都要扣除cerebro.broker.setcommission(commission=0.0001)# Add a FixedSize sizer according to the stakecerebro.addsizer(bt.sizers.FixedSize, stake=10)# Print out the starting conditionsprint('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())# Run over everythingcerebro.run()# Print out the final resultprint('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())cerebro.plot(iplot=False)#cerebro.plot() # Javascript Error: IPython is not defined

绘图结果如下:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/279320.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言写的 mini版的 http 服务器 , 很详细

文章目录 效果展示整体架构流程技术细节完整代码 效果展示 例如&#xff1a;htpp://192.168.23.140/home.html -> 正确的请求格式 home.html 这个资源是放在我们服务器里面的 , 并不是随便访问的资源,当然我们可以放很多的资源进去. 整体架构流程 整个实现的流…

我 爱 你

我爱你 可是我不敢说 我怕我说了 你会离我而去 我不怕你离去 可是我怕你离开了我 再没有人像我这样爱你 现代人说&#xff1a;初中生的爱情是一起回家&#xff0c;高中生的爱情是一起吃饭&#xff0c;大学生的爱情是一起睡觉&#xff0c;结婚了的爱情是一起回家吃饭然后…

LT7911D是TYPE-C/DP或者EDP转2 PORT MIPI和LVDS加音频

1.概述&#xff1a; T7911D是一款高性能TYPE-C/DP/EDP转2 PORT MIPI或者LVDS的芯片&#xff0c;目前主要在AR/VR或者显示器上应用的很多&#xff0c;对于DP1.2输入&#xff0c;LT7911D可配置为1/2/4车道。自适应均衡化使其适用于长电缆应用&#xff0c;最大带宽可达21.6Gbps。…

FGSM、PGD、BIM对抗攻击算法实现

本篇文章是博主在AI、无人机、强化学习等领域学习时&#xff0c;用于个人学习、研究或者欣赏使用&#xff0c;并基于博主对人工智能等领域的一些理解而记录的学习摘录和笔记&#xff0c;若有不当和侵权之处&#xff0c;指出后将会立即改正&#xff0c;还望谅解。文章分类在AI学…

win10电脑字体大小怎么设置?介绍四种方法

在Win10操作系统中&#xff0c;字体大小的设置对于用户来说是一个非常重要的问题。合适的字体大小能够保护我们的视力&#xff0c;提高我们的工作效率。本文将介绍几种常用的方法来调整Win10电脑的字体大小&#xff0c;帮助用户轻松设置自己喜欢的字体大小。 方法一&#xff1…

【C++11特性篇】C++11中新增的initializer_list——初始化的小利器(2)

前言 大家好吖&#xff0c;欢迎来到 YY 滴C11系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; 目录 一.探究std::initializer_list是什么…

让高清媒体无限畅享——Movist Pro for Mac推广文章

随着科技的迅猛发展&#xff0c;高清媒体已经成为我们日常生活中不可或缺的一部分。无论是观看电影、追剧、还是欣赏高清音乐视频&#xff0c;我们都希望能够获得最佳的视听体验。为了满足这一需求&#xff0c;我们向大家推荐一款强大的高清媒体播放器——Movist Pro for Mac。…

Redis新数据类型-Bitmaps

目录 Bitmaps 简介 命令 1. setbit (1) 格式 (2) 实例 2. getbit (1) 格式 (2) 实例 3. bitcount (1) 格式 (2) 实例 4. bitop (1) 格式 (2) 实例 我的其他博客 Bitmaps 简介 Bitmaps 是 Redis 的一种新数据类型&#xff0c;它是一种用于存储位信息的数据结构&…

进程优化软件(Process Lasso pro) v10.2.0.7-好用的系统优化软件-能够为用户提供超多专业的算法

调试进程级别的系统优化工具&#xff0c;主要功能是基于其特别的算法动态调整各个进程的优先级并设为合理的优先级以实现为系统减负的目的&#xff0c;可有效避免蓝屏、假死、进程停止响应、进程占用 CPU 时间过多等症状。同时它还具备前台进程推进、工作集修整、进程黑名单等附…

移动端机器学习框架 MDL 简介与实践

Mobile-deep-learning&#xff08;MDL&#xff09; MDL 是百度研发的可以部署在移动端的基于卷积神经网络实现的移动端框架&#xff0c;可以应用在图像识别领域。 具体应用&#xff1a;在手机百度 App 中&#xff0c;用户只需要点击自动拍开关&#xff0c;将手机对准物体&…

计算机组成原理-选择语句和循环语句的汇编表示

文章目录 选择语句jmpjxx示例&#xff1a;选择语句的机器级表示扩展&#xff1a;cmp指令的底层原理 循环语句使用条件转移指令实现循环用loop指令实现循环 选择语句 不一定知道指令的位置&#xff0c;所以jmp直接跳转到指令的位置很难办 jmp 标号相当于位置&#xff0c;名字…

点燃温暖时光:探索酒精壁炉的独特历史与现代化魅力

酒精壁炉的历史可以追溯到18世纪末。最初&#xff0c;人们用酒精在暖炉或炉子中燃烧&#xff0c;以获得热量。19世纪初&#xff0c;法国发明家提出了利用酒精燃烧来供暖的概念。这一概念被逐渐应用于家庭取暖装置&#xff0c;酒精壁炉也开始在欧洲兴起。 随着科技的发展&#x…