[增强功能] 开源资金曲线,renko_bar

This commit is contained in:
msincenselee 2020-06-06 22:17:36 +08:00
parent 732b6606ac
commit e327f49de6
4 changed files with 4601 additions and 31 deletions

View File

@ -36,8 +36,8 @@ gitee 链接: https://gitee.com/vnpy2/vnpy
- 提供cta_line_bar k线组件支持国内文华/交易师/TB等分钟/小时的计算模式,支持任意秒/分钟/小时/天/周等周期支持k线数据实时生成。 - 提供cta_line_bar k线组件支持国内文华/交易师/TB等分钟/小时的计算模式,支持任意秒/分钟/小时/天/周等周期支持k线数据实时生成。
- 提供cta_renko_bar k线组件支持x跳动/千分比跳动 【特定开源对象】 - 提供cta_renko_bar k线组件支持x跳动/千分比跳动
- 提供cta_fund_kline 资金曲线组件,策略实例/账号基本的实时资金曲线 【特定开源对象】 - 提供cta_fund_kline 资金曲线组件,策略实例/账号基本的实时资金曲线
- 提供cta_position 组件,支持多/空/净仓位记录,支持套利 - 提供cta_position 组件,支持多/空/净仓位记录,支持套利
- 提供cta_policy 组件,持久化复杂的策略执行逻辑 - 提供cta_policy 组件,持久化复杂的策略执行逻辑
- 提供cta_period 组件,支持策略中‘周期’的逻辑 - 提供cta_period 组件,支持策略中‘周期’的逻辑

View File

@ -0,0 +1,572 @@
# encoding: UTF-8
# 资金曲线 - 华富资产
# 账号级别资金曲线( 根据账号balance更新
# 策略实例级别资金曲线根据pnl计算
# 使用小时级别KLine计算
# 针对策略实例bar.open_interest 为平仓权益
# 2019/5/30
# 1. add load trade list function on init for strategy
# 2. add trade record function for strategy
# 2019/6/9
# 1. 增加renko bar的资金曲线
import os
from datetime import datetime
import pandas as pd
import traceback
from vnpy.component.cta_line_bar import CtaHourBar
from vnpy.component.cta_renko_bar import CtaRenkoBar
from vnpy.trader.object import BarData, TickData
from vnpy.trader.utility import get_folder_path, get_trading_date
from vnpy.trader.constant import Direction, Offset, Exchange
class FundKline(object):
def __init__(self, cta_engine, setting, use_cache=False, load_trade=False):
"""
初始化
:param cta_engine:
:param setting:
"""
self.cta_engine = cta_engine
self.kline = None
self.setting = setting
self.kline_name = setting.get('name')
self.kline_file = None
self.closed_profit = 0
self.holding_profit = 0
self.profit_list = []
self.holding_list = []
self.price_tick = self.setting.get('price_tick', 0.01)
self.symbol = self.setting.get('symbol', None)
if self.symbol is None:
vt_symbol = self.setting.get('vt_symbol', 'fund')
if '.' in vt_symbol:
self.symbol, _ = vt_symbol.split('.')
else:
self.symbol = vt_symbol
if self.kline_name is None:
self.write_error(u'setting没有配置资金曲线name变量')
return
# onbar 回调函数
self.onbar_callback = self.setting.pop('onbar_callback', None)
self.use_renko = self.setting.pop('use_renko', False)
if self.use_renko:
self.write_log(u'使用CtaRenkoBar')
self.kline = CtaRenkoBar(strategy=self, cb_on_bar=self.on_bar, setting=self.setting)
else:
self.write_log(u'使用CtaHourBar')
self.kline = CtaHourBar(strategy=self, cb_on_bar=self.on_bar, setting=self.setting)
# self.kline = CtaDayBar(strategy=self, onBarFunc=self.onBar, setting=self.setting)
self.inited = False
self.long_pos_dict = {}
self.short_pos_dict = {}
# 记载历史k线
if use_cache:
self.load()
else:
self.inited = True
# 加载历史交易记录,获取剩余持仓记录
if (load_trade):
self.load_trade_list()
def write_log(self, content, strategy_name=None):
"""
记录日志
:param content:
:return:
"""
if self.cta_engine:
self.cta_engine.write_log(content, strategy_name)
def write_error(self, content, strategy_name=None):
"""
记录充值日志
:param content:
:return:
"""
if self.cta_engine:
self.cta_engine.write_error(content, strategy_name)
def load(self):
"""
从本地csv文件恢复k线数据
:return:
"""
self.kline_file = str(get_folder_path('data').joinpath('fund_{}.csv'.format(self.kline_name)))
# 如果数据文件存在,则加载数据
if os.path.exists(self.kline_file):
self.write_log(u'加载{}数据'.format(self.kline_name))
df = pd.read_csv(self.kline_file)
dt_now = datetime.now()
df = df.set_index(pd.DatetimeIndex(df['datetime']))
for dt, bar_data in df.iterrows():
bar = BarData()
bar.symbol = self.symbol
bar.datetime = dt
bar.open_price = float(bar_data['open'])
bar.close_price = float(bar_data['close'])
bar.high_price = float(bar_data['high'])
bar.low_price = float(bar_data['low'])
bar.date = dt.strftime('%Y-%m-%d')
str_td = str(bar_data.get('trading_date', ''))
if len(str_td) == 8:
bar.trading_day = str_td[0:4] + '-' + str_td[4:6] + '-' + str_td[6:8]
elif len(str_td) == 0:
bar.trading_day = bar.date
else:
bar.trading_day = get_trading_date(dt)
bar.time = dt.strftime('%H:%M:%S')
bar.open_interest = float(bar_data.get('open_interest', 0))
if self.use_renko:
self.kline.add_bar(bar)
else:
# bar得时间与当前时间相隔超过一个小时加入完整得bar
if (dt_now - dt).total_seconds() > 60 * 60:
self.kline.add_bar(bar, bar_is_completed=True, bar_freq=60)
# 可能是最后一根bar
else:
self.write_log(u'更新最后一根Bar:{},now:{}'.format(dt, dt_now))
self.kline.add_bar(bar, bar_is_completed=False, bar_freq=dt.minute)
else:
self.write_log(u'当前没有资金历史K线文件:{}'.format(self.kline_file))
self.inited = True
# 设置 kline的输出文件
self.kline.export_filename = self.kline_file
self.kline.export_fields = [
{'name': 'datetime', 'source': 'bar', 'attr': 'datetime', 'type_': 'datetime'},
{'name': 'open', 'source': 'bar', 'attr': 'open_price', 'type_': 'float'},
{'name': 'high', 'source': 'bar', 'attr': 'high_price', 'type_': 'float'},
{'name': 'low', 'source': 'bar', 'attr': 'low_price', 'type_': 'float'},
{'name': 'close', 'source': 'bar', 'attr': 'close_price', 'type_': 'float'},
{'name': 'turnover', 'source': 'bar', 'attr': 'turnover', 'type_': 'float'},
{'name': 'volume', 'source': 'bar', 'attr': 'volume', 'type_': 'float'},
{'name': 'open_interest', 'source': 'bar', 'attr': 'open_interest', 'type_': 'float'}
]
def save(self):
"""保存数据"""
for bar in self.kline.line_bar:
self.kline.export_to_csv(bar)
def load_trade_list(self):
"""
加载策略的交易记录 data/xxxx_trade.csv
:return:
"""
trade_csv_file = str(get_folder_path('data').joinpath('{}_trade.csv'.format(self.kline_name)))
if not os.path.exists(trade_csv_file):
self.write_log('交易文件{} 不存在,不需要加载交易记录')
return
trade_df = pd.read_csv(trade_csv_file)
# 对交易记录进行处理,计算平仓盈亏
for _, row in trade_df.iterrows():
try:
direction = row.get('direction', None)
offset = row.get('offset', None)
price = row.get('price', None)
vt_symbol = row.get('vt_symbol', None)
volume = row.get('volume', None)
trade_time = row.get('time', None)
if 'SPD' in vt_symbol:
continue
# 如果开仓类型,放入队列
if direction == u'' and offset == u'开仓':
exist_buy_list = self.long_pos_dict.get(vt_symbol, [])
exist_buy_list.append({'volume': volume, 'price': price, 'open_time': trade_time})
self.long_pos_dict.update({vt_symbol: exist_buy_list})
continue
if direction == u'' and offset == u'开仓':
exist_short_list = self.short_pos_dict.get(vt_symbol, [])
exist_short_list.append({'volume': volume, 'price': price, 'open_time': trade_time})
self.short_pos_dict.update({vt_symbol: exist_short_list})
continue
if direction == u'' and offset in [u'平仓', u'平今', u'平昨']:
sell_volume = volume
exist_buy_list = self.long_pos_dict.get(vt_symbol, [])
# 循环一直到sell单被满足
while (sell_volume > 0):
if len(exist_buy_list) == 0:
self.write_log(u'{}没有足够的{}多单,数据不齐全,需要补全.{}'
.format(self.kline_name, vt_symbol, row), strategy_name=self.kline_name)
break
buy_trade = exist_buy_list.pop(0)
buy_volume = buy_trade.get('volume', 0)
open_time = buy_trade.get('open_time', None)
trade_volume = 0
if sell_volume <= buy_volume:
trade_volume = sell_volume
buy_trade.update({'volume': buy_volume - sell_volume})
sell_volume = 0
else:
sell_volume -= buy_volume
trade_volume = buy_volume
buy_trade.update({'volume': 0})
self.write_log(f'{open_time} {trade_volume} => selled')
# 仍然有剩余的多单
if buy_trade.get('volume', 0) > 0:
exist_buy_list.insert(0, buy_trade)
self.long_pos_dict.update({vt_symbol: exist_buy_list})
if direction == u'' and offset in [u'平仓', u'平今', u'平昨']:
cover_volume = volume
exist_short_list = self.short_pos_dict.get(vt_symbol, [])
# 循环一直到cover单被满足
while cover_volume > 0:
if len(exist_short_list) == 0:
self.write_error(u'{}没有足够的{}空单,数据不齐全,需要补全.{}'
.format(self.kline_name, vt_symbol, row), strategy_name=self.kline_name)
break
short_trade = exist_short_list.pop(0)
short_volume = short_trade.get('volume', 0)
open_time = short_trade.get('open_time', None)
trade_volume = 0
if cover_volume <= short_volume:
trade_volume = cover_volume
short_trade.update({'volume': short_volume - cover_volume})
cover_volume = 0
else:
cover_volume -= short_volume
trade_volume = short_volume
short_trade.update({'volume': 0})
self.write_log(f'{open_time} {trade_volume} => covered')
# 仍然有剩余的空单
if short_trade.get('volume', 0) > 0:
exist_short_list.insert(0, short_trade)
self.short_pos_dict.update({vt_symbol: exist_short_list})
except Exception as ex:
self.write_error(u'{}发生异常:{}'.format(self.kline_name, str(ex)))
pass
self.write_log(u'{}加载历史交易数据完毕'.format(self.kline_name))
if len(self.long_pos_dict) > 0:
self.write_log(u'记录得持仓多单:{}'.format(self.long_pos_dict))
if len(self.short_pos_dict) > 0:
self.write_log(u'记录得持仓空单:{}'.format(self.short_pos_dict))
def get_hold_pnl(self, log=False, update_list=False):
"""
获取持仓收益
:param: log 输出日志
:param: update_list: 更新self.holding_list
:return:
"""
all_holding_profit = 0.0
holded = False
# 计算所有多单的持仓盈亏
for vt_symbol, long_trade_list in self.long_pos_dict.items():
cur_price = self.cta_engine.get_price(vt_symbol)
if cur_price is None:
continue
cur_size = self.cta_engine.get_size(vt_symbol)
long_holding_profit = 0
traded = False
for buy_trade in long_trade_list:
open_price = buy_trade.get('price', 0)
cur_profit = (cur_price - open_price) * cur_size * buy_trade.get('volume')
long_holding_profit += cur_profit
traded = True
holded = True
if update_list:
holding_record = {'open_time': buy_trade.get('open_time'),
'vt_symbol': vt_symbol,
'open_action': 'Buy',
'volume': int(buy_trade.get('volume', 0)),
'open_price': float(buy_trade.get('price', 0.0)),
'cur_price': cur_price,
'cur_profit': cur_profit,
'holding_profit': long_holding_profit
}
self.holding_list.append(holding_record)
all_holding_profit += long_holding_profit
if log and traded:
self.write_log(u'{}多单持仓收益:{}'.format(vt_symbol, long_holding_profit), strategy_name=self.kline_name)
# 计算所有空单的持仓盈亏
for vt_symbol, short_trade_list in self.short_pos_dict.items():
cur_price = self.cta_engine.get_price(vt_symbol)
if cur_price is None:
continue
cur_size = self.cta_engine.get_size(vt_symbol)
short_holding_profit = 0
traded = False
for short_trade in short_trade_list:
open_price = short_trade.get('price', 0)
cur_profit = (open_price - cur_price) * cur_size * short_trade.get('volume')
short_holding_profit += cur_profit
traded = True
holded = True
if update_list:
holding_record = {'open_time': short_trade.get('open_time'),
'vt_symbol': vt_symbol,
'open_action': 'Buy',
'volume': int(short_trade.get('volume', 0)),
'open_price': float(short_trade.get('price', 0.0)),
'cur_price': cur_price,
'cur_profit': cur_profit,
'holding_profit': short_holding_profit
}
self.holding_list.append(holding_record)
all_holding_profit += short_holding_profit
if log and traded:
self.write_log(u'{}空单单持仓收益:{}'.format(vt_symbol, short_holding_profit), strategy_name=self.kline_name)
return all_holding_profit, holded
def on_bar(self, *args, **kwargs):
if self.onbar_callback and len(args) > 0:
try:
self.onbar_callback(*args, **kwargs)
except Exception as ex:
self.write_error(u'执行onbar回调函数异常:{},tb:{}'.format(str(ex), traceback.format_exc()))
def update_account(self, dt, balance):
"""
更新资金曲线
:param dt:
:param balance: 账号级别直接使用账号得的balance
:return:
"""
tick = TickData(
gateway_name='Fund',
symbol=self.symbol,
exchange=Exchange.LOCAL,
datetime=dt
)
tick.last_price = balance
tick.volume = 1
tick.ask_price_1 = balance
tick.ask_volume_1 = 1
tick.bid_price_1 = balance
tick.bid_volume_1 = 1
tick.date = tick.datetime.strftime('%Y-%m-%d')
tick.time = tick.datetime.strftime('%H:%M:%S')
tick.trading_day = get_trading_date(dt)
tick.open_interest = balance
if self.inited:
self.kline.on_tick(tick)
# 如果是从账号更新,无法更新持仓盈亏
self.closed_profit = balance
self.holding_profit = 0
def update_trade(self, trade):
"""
更新策略的交易记录
:param trade:
:return:
"""
try:
# 如果开仓类型,放入队列
if trade.direction == Direction.LONG and trade.offset == Offset.OPEN:
exist_buy_list = self.long_pos_dict.get(trade.vt_symbol, [])
exist_buy_list.append({'volume': trade.volume, 'price': trade.price, 'open_time': trade.time})
self.long_pos_dict.update({trade.vt_symbol: exist_buy_list})
self.write_log(u'更新{}的持仓记录:{}'.format(trade.vt_symbol, exist_buy_list))
return
if trade.direction == Direction.SHORT and trade.offset == Offset.OPEN:
exist_short_list = self.short_pos_dict.get(trade.vt_symbol, [])
exist_short_list.append({'volume': trade.volume, 'price': trade.price, 'open_time': trade.time})
self.short_pos_dict.update({trade.vt_symbol: exist_short_list})
self.write_log(u'更新{}的持仓记录:{}'.format(trade.vt_symbol, exist_short_list))
return
if trade.direction == Direction.SHORT and trade.offset in [Offset.CLOSE, Offset.CLOSETODAY,
Offset.CLOSEYESTERDAY]:
sell_volume = trade.volume
exist_buy_list = self.long_pos_dict.get(trade.vt_symbol, [])
close_profit = 0
# 循环一直到sell单被满足
while (sell_volume > 0):
if len(exist_buy_list) == 0:
self.write_error(
u'{}没有足够的{}多单记录,数据不齐全.{}'.format(self.kline_name, trade.vt_symbol, trade.__dict__))
return
buy_trade = exist_buy_list.pop(0)
buy_volume = buy_trade.get('volume', 0)
trade_volume = 0
if sell_volume <= buy_volume:
trade_volume = sell_volume
buy_trade.update({'volume': buy_volume - sell_volume})
sell_volume = 0
else:
sell_volume -= buy_volume
trade_volume = buy_volume
buy_trade.update({'volume': 0})
# 仍然有剩余的多单
if buy_trade.get('volume', 0) > 0:
exist_buy_list.insert(0, buy_trade)
self.long_pos_dict.update({trade.vt_symbol: exist_buy_list})
symbol_size = self.cta_engine.get_size(trade.vt_symbol)
cur_profit = (trade.price - float(buy_trade.get('price', 0.0))) * symbol_size * trade_volume
close_profit += cur_profit
self.closed_profit += cur_profit
profit_record = {'open_time': buy_trade.get('time'),
'vt_symbol': trade.vt_symbol,
'open_action': 'Buy',
'volume': trade_volume,
'open_price': buy_trade.get('price', 0.0),
'close_time': trade.time,
'close_price': trade.price,
'close_action': 'Sell',
'cur_profit': cur_profit,
'closed_profit': self.closed_profit
}
self.profit_list.append(profit_record)
trade_dt = datetime.now()
if len(trade.time) > 8 and ' ' in trade.time:
try:
trade_dt = datetime.strptime(trade.time, '%Y-%m-%d %H:%M:%S')
except Exception:
trade_dt = datetime.now()
hold_pnl, _ = self.get_hold_pnl(log=True)
self.update_strategy(dt=trade_dt, closed_pnl=close_profit, hold_pnl=hold_pnl)
cur_openIntesting = self.kline.line_bar[-1].open_interest if len(
self.kline.line_bar) > 0 else close_profit
self.write_log(u'{} 多单 {} => {}平仓,当前平仓收益:{},策略收益:{}'
.format(self.kline_name, trade.vt_symbol, trade.time,
close_profit, cur_openIntesting))
if trade.direction == Direction.LONG and trade.offset in [Offset.CLOSE, Offset.CLOSETODAY,
Offset.CLOSEYESTERDAY]:
cover_volume = trade.volume
exist_short_list = self.short_pos_dict.get(trade.vt_symbol, [])
close_profit = 0
# 循环一直到cover单被满足
while (cover_volume > 0):
if len(exist_short_list) == 0:
self.write_error(u'{}没有足够的{}空单,数据不齐全,数据需要补全.{}'
.format(self.kline_name, trade.vt_symbol, trade.__dict__))
return
short_trade = exist_short_list.pop(0)
short_volume = short_trade.get('volume', 0)
open_time = short_trade.get('open_time', None)
trade_volume = 0
if cover_volume <= short_volume:
trade_volume = cover_volume
short_trade.update({'volume': short_volume - cover_volume})
cover_volume = 0
else:
cover_volume -= short_volume
trade_volume = short_volume
short_trade.update({'volume': 0})
# 仍然有剩余的空单
if short_trade.get('volume', 0) > 0:
exist_short_list.insert(0, short_trade)
self.short_pos_dict.update({trade.vt_symbol: exist_short_list})
symbol_size = self.cta_engine.get_size(trade.vt_symbol)
cur_profit = (float(short_trade.get('price', 0.0)) - trade.price) * symbol_size * trade_volume
close_profit += cur_profit
self.closed_profit += cur_profit
profit_record = {'open_time': short_trade.get('time'),
'vt_symbol': trade.vt_symbol,
'open_action': 'Short',
'volume': trade_volume,
'open_price': short_trade.get('price', 0.0),
'close_time': trade.time,
'close_price': trade.price,
'close_action': 'Cover',
'cur_profit': cur_profit,
'closed_profit': self.closed_profit
}
self.profit_list.append(profit_record)
cur_openIntesting = self.kline.line_bar[-1].open_interest if len(
self.kline.line_bar) > 0 else close_profit
self.write_log(f'{self.kline_name} {open_time} {trade.vt_symbol}空单 => '
f'{trade.time} 平仓,累计平仓收益:{close_profit},策略收益:{cur_openIntesting}')
trade_dt = datetime.now()
if len(trade.time) > 8 and ' ' in trade.time:
try:
trade_dt = datetime.strptime(trade.time, '%Y-%m-%d %H:%M:%S')
except Exception:
trade_dt = datetime.now()
hold_pnl, _ = self.get_hold_pnl(log=True)
self.update_strategy(dt=trade_dt, closed_pnl=close_profit, hold_pnl=hold_pnl)
except Exception as ex:
self.write_error(u'更新策略{}交易记录异常:{}'.format(self.kline_name, str(ex)))
self.write_error(traceback.format_exc())
def update_strategy(self, dt, closed_pnl=0, hold_pnl=0):
"""
更新资金曲线
:param dt:
:param closed_pnl: 策略提供的平仓盈亏
:param hold_pnl: 策略提供的持仓盈亏
:return:
"""
# 获取当前bar的平仓权益
open_interest = 0
if len(self.kline.line_bar) > 0:
open_interest = self.kline.line_bar[-1].open_interest
if closed_pnl != 0:
self.write_log(u'策略平仓收益:{}->{}'.format(open_interest, open_interest + closed_pnl))
open_interest += closed_pnl
tick = TickData(gateway_name='Fund',
symbol=self.symbol,
exchange=Exchange.LOCAL,
datetime=dt)
tick.last_price = open_interest + hold_pnl
tick.volume = 1
tick.ask_price1 = open_interest + hold_pnl
tick.ask_volume1 = 1
tick.bid_price1 = open_interest + hold_pnl
tick.bid_volume1 = 1
tick.datetime = dt
tick.open_interest = open_interest
tick.date = tick.datetime.strftime('%Y-%m-%d')
tick.time = tick.datetime.strftime('%H:%M:%S')
tick.trading_day = get_trading_date(dt)
if self.inited:
self.kline.on_tick(tick)
self.closed_profit = open_interest
self.holding_profit = hold_pnl

View File

@ -1294,7 +1294,7 @@ class CtaLineBar(object):
if self.para_pre_len <= 0: # 不计算 if self.para_pre_len <= 0: # 不计算
return return
count_len = min(self.para_pre_len, self.bar_len) count_len = min(self.para_pre_len, self.bar_len - 1)
# 2.计算前self.para_pre_len周期内的Bar高点和低点(不包含当前周期因为当前正在合成的bar # 2.计算前self.para_pre_len周期内的Bar高点和低点(不包含当前周期因为当前正在合成的bar
# 还未触发on_bar不会存入开高低收序列 # 还未触发on_bar不会存入开高低收序列
@ -1487,7 +1487,7 @@ class CtaLineBar(object):
# 计算第一条MA均线 # 计算第一条MA均线
if self.para_ma1_len > 0: if self.para_ma1_len > 0:
count_len = min(self.para_ma1_len, self.bar_len) count_len = min(self.para_ma1_len, self.bar_len - 1)
barMa1 = ta.MA(self.close_array[-count_len:], count_len)[-1] barMa1 = ta.MA(self.close_array[-count_len:], count_len)[-1]
if np.isnan(barMa1): if np.isnan(barMa1):
@ -1508,7 +1508,7 @@ class CtaLineBar(object):
# 计算第二条MA均线 # 计算第二条MA均线
if self.para_ma2_len > 0: if self.para_ma2_len > 0:
count_len = min(self.para_ma2_len, self.bar_len) count_len = min(self.para_ma2_len, self.bar_len - 1)
barMa2 = ta.MA(self.close_array[-count_len:], count_len)[-1] barMa2 = ta.MA(self.close_array[-count_len:], count_len)[-1]
if np.isnan(barMa2): if np.isnan(barMa2):
return return
@ -1528,7 +1528,7 @@ class CtaLineBar(object):
# 计算第三条MA均线 # 计算第三条MA均线
if self.para_ma3_len > 0: if self.para_ma3_len > 0:
count_len = min(self.para_ma3_len, self.bar_len) count_len = min(self.para_ma3_len, self.bar_len - 1)
barMa3 = ta.MA(self.close_array[-count_len:], count_len)[-1] barMa3 = ta.MA(self.close_array[-count_len:], count_len)[-1]
if np.isnan(barMa3): if np.isnan(barMa3):
return return
@ -1725,7 +1725,7 @@ class CtaLineBar(object):
# 计算第一条EMA均线 # 计算第一条EMA均线
if self.para_ema1_len > 0: if self.para_ema1_len > 0:
count_len = min(self.para_ema1_len, self.bar_len) count_len = min(self.para_ema1_len, self.bar_len - 1)
# 3、获取前InputN周期(不包含当前周期的K线 # 3、获取前InputN周期(不包含当前周期的K线
barEma1 = ta.EMA(self.close_array[-ema1_data_len:], count_len)[-1] barEma1 = ta.EMA(self.close_array[-ema1_data_len:], count_len)[-1]
@ -1739,7 +1739,7 @@ class CtaLineBar(object):
# 计算第二条EMA均线 # 计算第二条EMA均线
if self.para_ema2_len > 0: if self.para_ema2_len > 0:
count_len = min(self.bar_len, self.para_ema2_len) count_len = min(self.bar_len - 1, self.para_ema2_len)
# 3、获取前InputN周期(不包含当前周期)的自适应均线 # 3、获取前InputN周期(不包含当前周期)的自适应均线
@ -1754,7 +1754,7 @@ class CtaLineBar(object):
# 计算第三条EMA均线 # 计算第三条EMA均线
if self.para_ema3_len > 0: if self.para_ema3_len > 0:
count_len = min(self.bar_len, self.para_ema3_len) count_len = min(self.bar_len - 1, self.para_ema3_len)
# 3、获取前InputN周期(不包含当前周期)的自适应均线 # 3、获取前InputN周期(不包含当前周期)的自适应均线
barEma3 = ta.EMA(self.close_array[-ema3_data_len:], count_len)[-1] barEma3 = ta.EMA(self.close_array[-ema3_data_len:], count_len)[-1]
@ -1982,7 +1982,7 @@ class CtaLineBar(object):
# 计算 ATR # 计算 ATR
if self.para_atr1_len > 0: if self.para_atr1_len > 0:
count_len = min(self.bar_len, self.para_atr1_len) count_len = min(self.bar_len - 1, self.para_atr1_len)
cur_atr1 = ta.ATR(self.high_array[-count_len * 2:], self.low_array[-count_len * 2:], cur_atr1 = ta.ATR(self.high_array[-count_len * 2:], self.low_array[-count_len * 2:],
self.close_array[-count_len * 2:], count_len) self.close_array[-count_len * 2:], count_len)
self.cur_atr1 = round(cur_atr1[-1], self.round_n) self.cur_atr1 = round(cur_atr1[-1], self.round_n)
@ -1991,7 +1991,7 @@ class CtaLineBar(object):
self.line_atr1.append(self.cur_atr1) self.line_atr1.append(self.cur_atr1)
if self.para_atr2_len > 0: if self.para_atr2_len > 0:
count_len = min(self.bar_len, self.para_atr2_len) count_len = min(self.bar_len - 1, self.para_atr2_len)
cur_atr2 = ta.ATR(self.high_array[-count_len * 2:], self.low_array[-count_len * 2:], cur_atr2 = ta.ATR(self.high_array[-count_len * 2:], self.low_array[-count_len * 2:],
self.close_array[-count_len * 2:], count_len) self.close_array[-count_len * 2:], count_len)
self.cur_atr2 = round(cur_atr2[-1], self.round_n) self.cur_atr2 = round(cur_atr2[-1], self.round_n)
@ -2000,7 +2000,7 @@ class CtaLineBar(object):
self.line_atr2.append(self.cur_atr2) self.line_atr2.append(self.cur_atr2)
if self.para_atr3_len > 0: if self.para_atr3_len > 0:
count_len = min(self.bar_len, self.para_atr3_len) count_len = min(self.bar_len - 1, self.para_atr3_len)
cur_atr3 = ta.ATR(self.high_array[-count_len * 2:], self.low_array[-count_len * 2:], cur_atr3 = ta.ATR(self.high_array[-count_len * 2:], self.low_array[-count_len * 2:],
self.close_array[-count_len * 2:], count_len) self.close_array[-count_len * 2:], count_len)
self.cur_atr3 = round(cur_atr3[-1], self.round_n) self.cur_atr3 = round(cur_atr3[-1], self.round_n)
@ -2017,8 +2017,8 @@ class CtaLineBar(object):
if self.para_vol_len <= 0: # 不计算 if self.para_vol_len <= 0: # 不计算
return return
bar_len = min(self.bar_len, self.para_vol_len) bar_len = min(self.bar_len - 1, self.para_vol_len)
sumVol = sum([x.volume for x in self.line_bar[-bar_len:]]) sumVol = sum([x.volume for x in self.line_bar[-bar_len - 1:-1]])
avgVol = round(sumVol / bar_len, 0) avgVol = round(sumVol / bar_len, 0)
if len(self.line_vol_ma) > self.max_hold_bars: if len(self.line_vol_ma) > self.max_hold_bars:
@ -2134,7 +2134,7 @@ class CtaLineBar(object):
self.write_log(u'数据未充分,当前Bar数据数量{0}计算Boll需要{1}'. self.write_log(u'数据未充分,当前Bar数据数量{0}计算Boll需要{1}'.
format(len(self.line_bar), min(14, self.para_boll_len) + 1)) format(len(self.line_bar), min(14, self.para_boll_len) + 1))
else: else:
bollLen = min(self.bar_len, self.para_boll_len) bollLen = min(self.bar_len - 1, self.para_boll_len)
# 不包含当前最新的Bar # 不包含当前最新的Bar
upper_list, middle_list, lower_list = ta.BBANDS(self.close_array, upper_list, middle_list, lower_list = ta.BBANDS(self.close_array,
@ -2195,7 +2195,7 @@ class CtaLineBar(object):
self.write_log(u'数据未充分,当前Bar数据数量{0}计算Boll2需要{1}'. self.write_log(u'数据未充分,当前Bar数据数量{0}计算Boll2需要{1}'.
format(len(self.line_bar), min(14, self.para_boll2_len) + 1)) format(len(self.line_bar), min(14, self.para_boll2_len) + 1))
else: else:
boll2Len = min(self.bar_len, self.para_boll2_len) boll2Len = min(self.bar_len - 1, self.para_boll2_len)
# 不包含当前最新的Bar # 不包含当前最新的Bar
upper_list, middle_list, lower_list = ta.BBANDS(self.close_array, upper_list, middle_list, lower_list = ta.BBANDS(self.close_array,
@ -2256,7 +2256,7 @@ class CtaLineBar(object):
self.write_log(u'数据未充分,当前Bar数据数量{0}计算Boll需要{1}'. self.write_log(u'数据未充分,当前Bar数据数量{0}计算Boll需要{1}'.
format(len(self.line_bar), min(14, self.para_boll_tb_len) + 1)) format(len(self.line_bar), min(14, self.para_boll_tb_len) + 1))
else: else:
bollLen = min(self.bar_len, self.para_boll_tb_len) bollLen = min(self.bar_len - 1, self.para_boll_tb_len)
# 不包含当前最新的Bar # 不包含当前最新的Bar
@ -2312,7 +2312,7 @@ class CtaLineBar(object):
self.write_log(u'数据未充分,当前Bar数据数量{0}计算Boll2需要{1}'. self.write_log(u'数据未充分,当前Bar数据数量{0}计算Boll2需要{1}'.
format(len(self.line_bar), min(14, self.para_boll2_tb_len) + 1)) format(len(self.line_bar), min(14, self.para_boll2_tb_len) + 1))
else: else:
boll2Len = min(self.bar_len, self.para_boll2_tb_len) boll2Len = min(self.bar_len - 1, self.para_boll2_tb_len)
if len(self.line_boll2_upper) > self.max_hold_bars: if len(self.line_boll2_upper) > self.max_hold_bars:
del self.line_boll2_upper[0] del self.line_boll2_upper[0]
@ -2565,7 +2565,7 @@ class CtaLineBar(object):
if self.para_kdj_smooth_len == 0: if self.para_kdj_smooth_len == 0:
self.para_kdj_smooth_len = 3 self.para_kdj_smooth_len = 3
inputKdjLen = min(self.para_kdj_len, self.bar_len) inputKdjLen = min(self.para_kdj_len, self.bar_len - 1)
hhv = max(self.high_array[-inputKdjLen:]) hhv = max(self.high_array[-inputKdjLen:])
llv = min(self.low_array[-inputKdjLen:]) llv = min(self.low_array[-inputKdjLen:])
@ -2680,7 +2680,7 @@ class CtaLineBar(object):
if self.bar_len < 3: if self.bar_len < 3:
return return
data_len = min(self.bar_len, self.para_kdj_tb_len) data_len = min(self.bar_len - 1, self.para_kdj_tb_len)
hhv = max(self.high_array[-data_len:]) hhv = max(self.high_array[-data_len:])
llv = min(self.low_array[-data_len:]) llv = min(self.low_array[-data_len:])
@ -2808,13 +2808,13 @@ class CtaLineBar(object):
maxLen = max(self.para_macd_fast_len, self.para_macd_slow_len) + self.para_macd_signal_len maxLen = max(self.para_macd_fast_len, self.para_macd_slow_len) + self.para_macd_signal_len
maxLen = maxLen * 3 # 注数据长度需要足够才能准确。测试过3倍长度才可以与国内的文华等软件一致 # maxLen = maxLen * 3 # 注数据长度需要足够才能准确。测试过3倍长度才可以与国内的文华等软件一致
if self.bar_len < maxLen: if self.bar_len - 1 < maxLen:
self.write_log(u'数据未充分,当前Bar数据数量{0}计算MACD需要{1}'.format(len(self.line_bar), maxLen)) self.write_log(u'数据未充分,当前Bar数据数量{0}计算MACD需要{1}'.format(self.bar_len - 1, maxLen))
return return
dif_list, dea_list, macd_list = ta.MACD(self.close_array[-2 * maxLen:], fastperiod=self.para_macd_fast_len, dif_list, dea_list, macd_list = ta.MACD(self.close_array, fastperiod=self.para_macd_fast_len,
slowperiod=self.para_macd_slow_len, slowperiod=self.para_macd_slow_len,
signalperiod=self.para_macd_signal_len) signalperiod=self.para_macd_signal_len)
if np.isnan(dif_list[-1]) or np.isnan(dea_list[-1]) or np.isnan(macd_list[-1]): if np.isnan(dif_list[-1]) or np.isnan(dea_list[-1]) or np.isnan(macd_list[-1]):
@ -3223,7 +3223,7 @@ class CtaLineBar(object):
observation=self.close_array[-1]) observation=self.close_array[-1])
m = state_means[-1].item() m = state_means[-1].item()
c = state_covariances[-1].item() c = state_covariances[-1].item()
std_len = 26 if self.bar_len > 26 else self.bar_len std_len = 26 if self.bar_len - 1 > 26 else self.bar_len - 1
std = np.std(self.close_array[-std_len:], ddof=1) std = np.std(self.close_array[-std_len:], ddof=1)
self.cur_state_std = std self.cur_state_std = std
if len(self.line_state_mean) > self.max_hold_bars: if len(self.line_state_mean) > self.max_hold_bars:
@ -3503,7 +3503,7 @@ class CtaLineBar(object):
return return
data_len = max(self.para_skd_fast_len * 2, self.para_skd_fast_len + 20) data_len = max(self.para_skd_fast_len * 2, self.para_skd_fast_len + 20)
if self.bar_len < data_len: if self.bar_len - 1 < data_len:
return return
# 计算最后一根Bar的RSI指标 # 计算最后一根Bar的RSI指标
@ -3966,7 +3966,7 @@ class CtaLineBar(object):
# format(len(self.lineBar), 4 * self.inputYbLen)) # format(len(self.lineBar), 4 * self.inputYbLen))
# return # return
ema_len = min(self.bar_len, self.para_yb_len) ema_len = min(self.bar_len - 1, self.para_yb_len)
if ema_len < 3: if ema_len < 3:
self.write_log(u'数据未充分,当前Bar数据数量{0}'. self.write_log(u'数据未充分,当前Bar数据数量{0}'.
format(len(self.line_bar))) format(len(self.line_bar)))
@ -4027,7 +4027,7 @@ class CtaLineBar(object):
return return
if self.bar_len < 2: if self.bar_len < 2:
return return
bar_len = min(self.para_golden_n, self.bar_len) bar_len = min(self.para_golden_n, self.bar_len - 1)
hhv = max(self.high_array[-bar_len:]) hhv = max(self.high_array[-bar_len:])
llv = min(self.low_array[-bar_len:]) llv = min(self.low_array[-bar_len:])
@ -4117,7 +4117,7 @@ class CtaLineBar(object):
format(len(self.line_bar), min(14, self.para_bias_len) + 1)) format(len(self.line_bar), min(14, self.para_bias_len) + 1))
else: else:
BiasLen = min(self.para_bias_len, self.bar_len) BiasLen = min(self.para_bias_len, self.bar_len - 1)
# 计算BIAS # 计算BIAS
m = np.mean(self.close_array[-BiasLen:]) m = np.mean(self.close_array[-BiasLen:])
@ -4133,7 +4133,7 @@ class CtaLineBar(object):
self.write_log(u'数据未充分,当前Bar数据数量{0}计算Bias2需要{1}'. self.write_log(u'数据未充分,当前Bar数据数量{0}计算Bias2需要{1}'.
format(len(self.line_bar), min(14, self.para_bias2_len) + 1)) format(len(self.line_bar), min(14, self.para_bias2_len) + 1))
else: else:
Bias2Len = min(self.bar_len, self.para_bias2_len) Bias2Len = min(self.bar_len - 1, self.para_bias2_len)
# 计算BIAS2 # 计算BIAS2
m = np.mean(self.close_array[-Bias2Len:]) m = np.mean(self.close_array[-Bias2Len:])
bias2 = (self.close_array[-1] - m) / m * 100 bias2 = (self.close_array[-1] - m) / m * 100
@ -4147,7 +4147,7 @@ class CtaLineBar(object):
self.write_log(u'数据未充分,当前Bar数据数量{0}计算Bias3需要{1}'. self.write_log(u'数据未充分,当前Bar数据数量{0}计算Bias3需要{1}'.
format(len(self.line_bar), min(14, self.para_bias3_len) + 1)) format(len(self.line_bar), min(14, self.para_bias3_len) + 1))
else: else:
Bias3Len = min(self.bar_len, self.para_bias3_len) Bias3Len = min(self.bar_len - 1, self.para_bias3_len)
# 计算BIAS3 # 计算BIAS3
m = np.mean(self.close_array[-Bias3Len:]) m = np.mean(self.close_array[-Bias3Len:])
bias3 = (self.close_array[-1] - m) / m * 100 bias3 = (self.close_array[-1] - m) / m * 100

File diff suppressed because it is too large Load Diff