Module backtrader.observers.trades
Expand source code
#!/usr/bin/env python
# -*- coding: utf-8; py-indent-offset:4 -*-
###############################################################################
#
# Copyright (C) 2015-2023 Daniel Rodriguez
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import uuid
from .. import Observer
from ..utils.py3 import with_metaclass
from ..trade import Trade
class Trades(Observer):
'''This observer keeps track of full trades and plot the PnL level achieved
when a trade is closed.
A trade is open when a position goes from 0 (or crossing over 0) to X and
is then closed when it goes back to 0 (or crosses over 0 in the opposite
direction)
Params:
- ``pnlcomm`` (def: ``True``)
Show net/profit and loss, i.e.: after commission. If set to ``False``
if will show the result of trades before commission
'''
_stclock = True
lines = ('pnlplus', 'pnlminus')
params = dict(pnlcomm=True)
plotinfo = dict(plot=True, subplot=True,
plotname='Trades - Net Profit/Loss',
plotymargin=0.10,
plothlines=[0.0])
plotlines = dict(
pnlplus=dict(_name='Positive',
ls='', marker='o', color='blue',
markersize=8.0, fillstyle='full'),
pnlminus=dict(_name='Negative',
ls='', marker='o', color='red',
markersize=8.0, fillstyle='full')
)
def __init__(self):
self.trades = 0
self.trades_long = 0
self.trades_short = 0
self.trades_plus = 0
self.trades_minus = 0
self.trades_plus_gross = 0
self.trades_minus_gross = 0
self.trades_win = 0
self.trades_win_max = 0
self.trades_win_min = 0
self.trades_loss = 0
self.trades_loss_max = 0
self.trades_loss_min = 0
self.trades_length = 0
self.trades_length_max = 0
self.trades_length_min = 0
def next(self):
for trade in self._owner._tradespending:
if trade.data not in self.ddatas:
continue
if not trade.isclosed:
continue
pnl = trade.pnlcomm if self.p.pnlcomm else trade.pnl
if pnl >= 0.0:
self.lines.pnlplus[0] = pnl
else:
self.lines.pnlminus[0] = pnl
class MetaDataTrades(Observer.__class__):
def donew(cls, *args, **kwargs):
_obj, args, kwargs = super(MetaDataTrades, cls).donew(*args, **kwargs)
# Recreate the lines dynamically
if _obj.params.usenames:
lnames = tuple(x._name for x in _obj.datas)
else:
lnames = tuple('data{}'.format(x) for x in range(len(_obj.datas)))
# Generate a new lines class
linescls = cls.lines._derive(uuid.uuid4().hex, lnames, 0, ())
# Instantiate lines
_obj.lines = linescls()
# Generate plotlines info
markers = ['o', 'v', '^', '<', '>', '1', '2', '3', '4', '8', 's', 'p',
'*', 'h', 'H', '+', 'x', 'D', 'd']
colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k', 'b', 'g', 'r', 'c', 'm',
'y', 'k', 'b', 'g', 'r', 'c', 'm']
basedict = dict(ls='', markersize=8.0, fillstyle='full')
plines = dict()
for lname, marker, color in zip(lnames, markers, colors):
plines[lname] = d = basedict.copy()
d.update(marker=marker, color=color)
plotlines = cls.plotlines._derive(
uuid.uuid4().hex, plines, [], recurse=True)
_obj.plotlines = plotlines()
return _obj, args, kwargs # return the instantiated object and args
class DataTrades(with_metaclass(MetaDataTrades, Observer)):
_stclock = True
params = (('usenames', True),)
plotinfo = dict(plot=True, subplot=True, plothlines=[0.0],
plotymargin=0.10)
plotlines = dict()
def next(self):
for trade in self._owner._tradespending:
if trade.data not in self.ddatas:
continue
if not trade.isclosed:
continue
self.lines[trade.data._id - 1][0] = trade.pnl
Classes
class DataTrades (*args, **kwargs)
-
Base class for LineXXX instances that hold more than one line
Expand source code
class DataTrades(with_metaclass(MetaDataTrades, Observer)): _stclock = True params = (('usenames', True),) plotinfo = dict(plot=True, subplot=True, plothlines=[0.0], plotymargin=0.10) plotlines = dict() def next(self): for trade in self._owner._tradespending: if trade.data not in self.ddatas: continue if not trade.isclosed: continue self.lines[trade.data._id - 1][0] = trade.pnl
Ancestors
Class variables
var alias
var aliased
var frompackages
var linealias
var packages
var params
var plotinfo
var plotlines
Inherited members
class MetaDataTrades (*args, **kwargs)
-
Dirty job manager for a LineSeries
-
During new (class creation), it reads "lines", "plotinfo", "plotlines" class variable definitions and turns them into Classes of type Lines or AutoClassInfo (plotinfo/plotlines)
-
During "new" (instance creation) the lines/plotinfo/plotlines classes are substituted in the instance with instances of the aforementioned classes and aliases are added for the "lines" held in the "lines" instance
Additionally and for remaining kwargs, these are matched against args in plotinfo and if existent are set there and removed from kwargs
Remember that this Metaclass has a MetaParams (from metabase) as root class and therefore "params" defined for the class have been removed from kwargs at an earlier state
Expand source code
class MetaDataTrades(Observer.__class__): def donew(cls, *args, **kwargs): _obj, args, kwargs = super(MetaDataTrades, cls).donew(*args, **kwargs) # Recreate the lines dynamically if _obj.params.usenames: lnames = tuple(x._name for x in _obj.datas) else: lnames = tuple('data{}'.format(x) for x in range(len(_obj.datas))) # Generate a new lines class linescls = cls.lines._derive(uuid.uuid4().hex, lnames, 0, ()) # Instantiate lines _obj.lines = linescls() # Generate plotlines info markers = ['o', 'v', '^', '<', '>', '1', '2', '3', '4', '8', 's', 'p', '*', 'h', 'H', '+', 'x', 'D', 'd'] colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k', 'b', 'g', 'r', 'c', 'm', 'y', 'k', 'b', 'g', 'r', 'c', 'm'] basedict = dict(ls='', markersize=8.0, fillstyle='full') plines = dict() for lname, marker, color in zip(lnames, markers, colors): plines[lname] = d = basedict.copy() d.update(marker=marker, color=color) plotlines = cls.plotlines._derive( uuid.uuid4().hex, plines, [], recurse=True) _obj.plotlines = plotlines() return _obj, args, kwargs # return the instantiated object and args
Ancestors
- MetaObserver
- MetaLineIterator
- MetaLineSeries
- MetaLineRoot
- MetaParams
- MetaBase
- builtins.type
Inherited members
-
class Trades
-
This observer keeps track of full trades and plot the PnL level achieved when a trade is closed.
A trade is open when a position goes from 0 (or crossing over 0) to X and is then closed when it goes back to 0 (or crosses over 0 in the opposite direction)
Params
pnlcomm
(def:True
)
Show net/profit and loss, i.e.: after commission. If set to
False
if will show the result of trades before commissionExpand source code
class Trades(Observer): '''This observer keeps track of full trades and plot the PnL level achieved when a trade is closed. A trade is open when a position goes from 0 (or crossing over 0) to X and is then closed when it goes back to 0 (or crosses over 0 in the opposite direction) Params: - ``pnlcomm`` (def: ``True``) Show net/profit and loss, i.e.: after commission. If set to ``False`` if will show the result of trades before commission ''' _stclock = True lines = ('pnlplus', 'pnlminus') params = dict(pnlcomm=True) plotinfo = dict(plot=True, subplot=True, plotname='Trades - Net Profit/Loss', plotymargin=0.10, plothlines=[0.0]) plotlines = dict( pnlplus=dict(_name='Positive', ls='', marker='o', color='blue', markersize=8.0, fillstyle='full'), pnlminus=dict(_name='Negative', ls='', marker='o', color='red', markersize=8.0, fillstyle='full') ) def __init__(self): self.trades = 0 self.trades_long = 0 self.trades_short = 0 self.trades_plus = 0 self.trades_minus = 0 self.trades_plus_gross = 0 self.trades_minus_gross = 0 self.trades_win = 0 self.trades_win_max = 0 self.trades_win_min = 0 self.trades_loss = 0 self.trades_loss_max = 0 self.trades_loss_min = 0 self.trades_length = 0 self.trades_length_max = 0 self.trades_length_min = 0 def next(self): for trade in self._owner._tradespending: if trade.data not in self.ddatas: continue if not trade.isclosed: continue pnl = trade.pnlcomm if self.p.pnlcomm else trade.pnl if pnl >= 0.0: self.lines.pnlplus[0] = pnl else: self.lines.pnlminus[0] = pnl
Ancestors
Class variables
var alias
var aliased
var frompackages
var linealias
var packages
var params
var plotinfo
var plotlines
Inherited members