Backtrader 文档学习-Quickstart

Backtrader 文档学习-Quickstart

0. 前言

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

如果将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.mzph.cn/news/217113.shtml

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

相关文章

DNS漫游指南:从网址到IP的奇妙之旅

当用户在浏览器中输入特定网站时发生的整个端到端过程可以参考下图 1*4vb-NMUuYTzYBYUFSuSKLw.png 问题&#xff1a; 什么是 DNS&#xff1f; 答案 → DNS 指的是域名系统&#xff08;Domain Name System&#xff09;。DNS 是互联网的目录&#xff0c;将人类可读的域名&#…

cobalt strike基础使用

coblat strike使用 服务搭建 首先将server端文件放进kali中 对其赋权 执行时需要root权限 设置ip 启动服务 ./teamserver 10.4.7.138 123456回到win11启动cs&#xff0c;输入刚才配置的信息 上线方式 木马&#xff08;exe上线&#xff09; 查看一下开放的端口 添加监听 …

最新科研成果:在钻石中存储多比特数据,实现25GB数据密度

近日&#xff0c;纽约城市大学&#xff08;CUNY&#xff09;的研究人员已经成功地利用钻石原子结构中的小型氮缺陷作为“颜色中心”来写入数据进行存储&#xff08;然后是检索&#xff09;。这项发表在《自然纳米技术》上的技术允许通过将数据编码为多个光频率&#xff08;即颜…

T5论文个人记录

参考&转载自&#xff1a; 介绍Google推出的大一统模型—T5_谷歌大模型_深度之眼的博客-CSDN博客 T5 和 mT5-CSDN博客 T5&#xff1a;Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer&#xff08;万字长文略解T5&#xff09;_t5论文…

tomcat软件部署

1.tomcat 2.tomcat功能组件 3.请求过程 4.tomcat部署 一.tomcat tomcat 是 Java 语言开发的&#xff0c;Tomcat 服务器是一个免费的开放源代码的 Web 应用服务器&#xff0c;却不如nginx&#xff0c;apache功能强大&#xff0c;通常作为 Servlet 和 JSP容器&#xff0c;单…

2023 CCF中国软件大会(CCF ChinaSoft)“软件定义汽车”论坛成功召开

2023年12月1日下午&#xff0c;2023年度CCF中国软件大会“软件定义汽车”论坛成功召开。 本次论坛由华东师范大学蒲戈光教授、武汉光庭信息技术股份有限公司朱敦尧董事长以及华东师范大学张越龄副教授联合组织举办。论坛主要关注汽车的智能网联化与电动化的融合&#xff0c;包括…

scala方法与函数

定义方法定义函数方法和函数的区别scala的方法函数操作 1.9 方法与函数 1.9.1 定义方法 定义方法的基本格式是&#xff1a; def 方法名称&#xff08;参数列表&#xff09;&#xff1a;返回值类型 方法体 def add(x: Int, y: Int): Int x y println(add(1, 2)) // 3 //也…

揭秘高效大型语言模型:技术、方法与应用展望

近年来&#xff0c;大型语言模型&#xff08;LLMs&#xff09;在自然语言处理领域取得了显著的进展&#xff0c;如GPT-series(GPT-3, GPT-4)、Google-series(Gemini, PaLM), Meta-series(LLAMA1&2), BLOOM, GLM等模型在各种任务中展现出惊人的能力。然而&#xff0c;随着模…

初学python的体会心得20字,初学python的体会心得2000

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;学了python的心得体会200字&#xff0c;初学python的体会心得20字&#xff0c;现在让我们一起来看看吧&#xff01; 本学期&#xff0c;我们学习了杨老师的《python语言程序设计》这门课程&#xff0c;其实早在大一期间…

人工智能导论习题集(1)

第二章&#xff1a;知识表示 题1题2题3题4题5 题1 题2 题3 题4 题5

HarmonyOS创建一个page并实现界面跳转(JavaScript)

上文 HarmonyOS创建JavaScript(类 Web开发模式)项目中 我们接触了这咋类Web开发模式 并创建了一个项目 之前 我们 ArkTS 开发模式的项目 resources目录 下的 base目录下的 profile目录下的 main_pages.json中存放了 我们page目录的配置 但是 我们javaScript模式 下 好像没有哦 …

DataFunSummit:2023年数据治理在线峰会-核心PPT资料下载

一、峰会简介 数据治理&#xff08;Data Governance&#xff09;是组织中涉及数据使用的一整套管理行为。由企业数据治理部门发起并推行&#xff0c;关于如何制定和实施针对整个企业内部数据的商业应用和技术管理的一系列政策和流程。 数据治理是一个通过一系列信息相关的过程…

披荆斩棘的「矿区无人驾驶」,能否真正打开千亿级市场?

随着2022年备受瞩目的台泥句容矿无人驾驶运输项目硬核落地&#xff0c;以及相关科技公司开放该矿24小时无人矿卡生产运营直播以证明其项目并非在演示&#xff0c;2023年全国开启了大规模矿区无人驾驶商业化落地&#xff0c;堪称矿区无人驾驶元年。虽然我国矿区无人驾驶市场渗透…

zookeeper集群介绍

一个leader&#xff0c;多个follower&#xff0c;组成的集群 集群中只要有半数以上得节点存活&#xff0c;zookeeper集群就能正常服务 顺序一致性&#xff1a; 来自同一个client的更新请求按其发送顺序依次执行 原子性&#xff1a; 更新操作要么成功要么失败&#xff0c; 没有…

flink-1.17.2的单节点部署

flink 简介 Apache Flink 是一个开源的流处理和批处理框架&#xff0c;用于大数据处理和分析。它旨在以实时和批处理模式高效处理大量数据。Flink 支持事件时间处理、精确一次语义、有状态计算等关键功能。 以下是与Apache Flink相关的一些主要特性和概念&#xff1a; 流处理…

养牛场北斗综合管理系统解决方案

1.系统架构 随着我国北斗卫星导航定位系统的快速发展和定位精度的持续不断提高&#xff0c;在牛身上穿戴定位终端后可以实现对牛的位置和温度的测量&#xff0c;在蜂窝网络正常的情况下&#xff0c;定位和温度数据通过蜂窝网络通信方式回传到监控云平台&#xff0c;在蜂窝网络缺…

uniapp实现拨打电话跳转手机拨号界面 (ios和安卓通用)

效果展示&#xff1a;左边为安卓系统展示&#xff0c;右边为ios系统展示 代码&#xff1a; toPhone(){uni.makePhoneCall({phoneNumber: "10086", //要拨打的手机号success: (res) > {// console.log("调用成功")},fail: (res) > {// console.log(调…

784. 字母大小写全排列 dfs + 回溯算法 + 图解 + 笔记

784. 字母大小写全排列 - 力扣&#xff08;LeetCode&#xff09; 给定一个字符串 s &#xff0c;通过将字符串 s 中的每个字母转变大小写&#xff0c;我们可以获得一个新的字符串。 返回 所有可能得到的字符串集合 。以 任意顺序 返回输出 示例 1&#xff1a; 输入&#xf…

MySQL的事务以及springboot中如何使用事务

事务的四大特性&#xff1a; 概念&#xff1a; 事务 是一组操作的集合&#xff0c;它是不可分割的工作单元。事务会把所有操作作为一个整体&#xff0c;一起向系统提交或撤销操作请求&#xff0c;即这些操作要么同时成功&#xff0c;要么同时失败。 注意&#xff1a; 默认MySQ…

sylar高性能服务器-配置(P10-p11)代码解析+调试分析

文章目录 p9&#xff1a;配置模块搭建一、ConfigvarBase二、ConfigVar三、Config四、小结 p10&#xff1a;YAML的使用一、安装yaml-cpp二、使用yaml-cpp三、代码解析 P11&#xff1a;YAML与日志的整合一、方法函数二、代码调试三、test_config结果四、小结 p9&#xff1a;配置模…