pybottrader.traders
A collection of bottraders
Traders, these are bots that based on a data stream, a strategy, and a portfolio, run the trading operations. Currently only a basic Trader is offered, useful for back-testing.
1""" 2A collection of bottraders 3 4Traders, these are bots that based on a data stream, a strategy, and a 5portfolio, run the trading operations. Currently only a basic Trader is offered, 6useful for back-testing. 7 8""" 9 10from typing import Union 11from attrs import define 12from .datastreamers import DataStreamer 13from .portfolios import Portfolio 14from .strategies import Strategy, Position, StrategySignal 15from .indicators import roi 16 17 18@define 19class TradingIteration: 20 """Used to report results from a trading iteration""" 21 22 signal: StrategySignal 23 data: dict 24 roi: Union[float, None] 25 portfolio_value: float 26 accumulated_roi: Union[float, None] 27 28 29class Trader: 30 """Base class""" 31 32 portfolio: Portfolio 33 datastream: DataStreamer 34 strategy: Strategy 35 last_result: Union[TradingIteration, None] = None 36 last_valuation: float = 0.0 37 38 def __init__( 39 self, 40 strategy: Strategy, 41 portfolio: Portfolio, 42 datastream: DataStreamer, 43 ): 44 """Init method""" 45 self.datastream = datastream 46 self.portfolio = portfolio 47 self.strategy = strategy 48 49 def next(self) -> bool: 50 """Perfoms a trading iteration""" 51 obs = self.datastream.next() 52 if obs is None: 53 return False 54 signal = self.strategy.evaluate(data=obs) 55 self.portfolio.process(signal) 56 self.last_result = TradingIteration( 57 signal=signal, 58 data=obs, 59 roi=roi(self.last_valuation, self.portfolio.valuation()), 60 portfolio_value=self.portfolio.valuation(), 61 accumulated_roi=self.portfolio.accumulated_return(), 62 ) 63 self.last_valuation = self.portfolio.valuation() 64 return True 65 66 def status(self) -> TradingIteration: 67 """Trader last result""" 68 return self.last_result 69 70 def run(self): 71 """A default runner""" 72 # A nice header 73 print( 74 "{:25} {:4} {:>10} {:>10} {:>10} {:>10}".format( # pylint: disable=consider-using-f-string 75 "Time", "Pos.", "Price", "ROI", "Valuation", "Accum.ROI" 76 ) 77 ) 78 # Run the back-testing 79 while self.next(): 80 status = self.status() 81 if status.signal.position != Position.STAY: 82 # A nice output 83 print( 84 f"{status.signal.time} " 85 + f"{status.signal.position.name:4} " 86 + f"{status.data['close']:10.2f} " 87 + f"{status.roi * 100.0:10.2f}% " 88 + f"{status.portfolio_value:10.2f} " 89 + f"{status.accumulated_roi * 100.0:10.2f}%" 90 )
@define
class
TradingIteration:
19@define 20class TradingIteration: 21 """Used to report results from a trading iteration""" 22 23 signal: StrategySignal 24 data: dict 25 roi: Union[float, None] 26 portfolio_value: float 27 accumulated_roi: Union[float, None]
Used to report results from a trading iteration
TradingIteration( signal: pybottrader.strategies.StrategySignal, data: dict, roi: Optional[float], portfolio_value: float, accumulated_roi: Optional[float])
2def __init__(self, signal, data, roi, portfolio_value, accumulated_roi): 3 self.signal = signal 4 self.data = data 5 self.roi = roi 6 self.portfolio_value = portfolio_value 7 self.accumulated_roi = accumulated_roi
Method generated by attrs for class TradingIteration.
class
Trader:
30class Trader: 31 """Base class""" 32 33 portfolio: Portfolio 34 datastream: DataStreamer 35 strategy: Strategy 36 last_result: Union[TradingIteration, None] = None 37 last_valuation: float = 0.0 38 39 def __init__( 40 self, 41 strategy: Strategy, 42 portfolio: Portfolio, 43 datastream: DataStreamer, 44 ): 45 """Init method""" 46 self.datastream = datastream 47 self.portfolio = portfolio 48 self.strategy = strategy 49 50 def next(self) -> bool: 51 """Perfoms a trading iteration""" 52 obs = self.datastream.next() 53 if obs is None: 54 return False 55 signal = self.strategy.evaluate(data=obs) 56 self.portfolio.process(signal) 57 self.last_result = TradingIteration( 58 signal=signal, 59 data=obs, 60 roi=roi(self.last_valuation, self.portfolio.valuation()), 61 portfolio_value=self.portfolio.valuation(), 62 accumulated_roi=self.portfolio.accumulated_return(), 63 ) 64 self.last_valuation = self.portfolio.valuation() 65 return True 66 67 def status(self) -> TradingIteration: 68 """Trader last result""" 69 return self.last_result 70 71 def run(self): 72 """A default runner""" 73 # A nice header 74 print( 75 "{:25} {:4} {:>10} {:>10} {:>10} {:>10}".format( # pylint: disable=consider-using-f-string 76 "Time", "Pos.", "Price", "ROI", "Valuation", "Accum.ROI" 77 ) 78 ) 79 # Run the back-testing 80 while self.next(): 81 status = self.status() 82 if status.signal.position != Position.STAY: 83 # A nice output 84 print( 85 f"{status.signal.time} " 86 + f"{status.signal.position.name:4} " 87 + f"{status.data['close']:10.2f} " 88 + f"{status.roi * 100.0:10.2f}% " 89 + f"{status.portfolio_value:10.2f} " 90 + f"{status.accumulated_roi * 100.0:10.2f}%" 91 )
Base class
Trader( strategy: pybottrader.strategies.Strategy, portfolio: pybottrader.portfolios.Portfolio, datastream: pybottrader.datastreamers.DataStreamer)
39 def __init__( 40 self, 41 strategy: Strategy, 42 portfolio: Portfolio, 43 datastream: DataStreamer, 44 ): 45 """Init method""" 46 self.datastream = datastream 47 self.portfolio = portfolio 48 self.strategy = strategy
Init method
portfolio: pybottrader.portfolios.Portfolio
datastream: pybottrader.datastreamers.DataStreamer
strategy: pybottrader.strategies.Strategy
def
next(self) -> bool:
50 def next(self) -> bool: 51 """Perfoms a trading iteration""" 52 obs = self.datastream.next() 53 if obs is None: 54 return False 55 signal = self.strategy.evaluate(data=obs) 56 self.portfolio.process(signal) 57 self.last_result = TradingIteration( 58 signal=signal, 59 data=obs, 60 roi=roi(self.last_valuation, self.portfolio.valuation()), 61 portfolio_value=self.portfolio.valuation(), 62 accumulated_roi=self.portfolio.accumulated_return(), 63 ) 64 self.last_valuation = self.portfolio.valuation() 65 return True
Perfoms a trading iteration
def
run(self):
71 def run(self): 72 """A default runner""" 73 # A nice header 74 print( 75 "{:25} {:4} {:>10} {:>10} {:>10} {:>10}".format( # pylint: disable=consider-using-f-string 76 "Time", "Pos.", "Price", "ROI", "Valuation", "Accum.ROI" 77 ) 78 ) 79 # Run the back-testing 80 while self.next(): 81 status = self.status() 82 if status.signal.position != Position.STAY: 83 # A nice output 84 print( 85 f"{status.signal.time} " 86 + f"{status.signal.position.name:4} " 87 + f"{status.data['close']:10.2f} " 88 + f"{status.roi * 100.0:10.2f}% " 89 + f"{status.portfolio_value:10.2f} " 90 + f"{status.accumulated_roi * 100.0:10.2f}%" 91 )
A default runner