Giter VIP home page Giter VIP logo

atreyu-backtrader-api's Introduction

Introduction

Currently backtrader has a built-in integration for Interactive Brokers (IB) Trader Workstation API, but it only works for older versions of the API.

This project re-worked the orginal integration and created a pluggable version allowing backtrader to use the latest IB API.

To start trading follow the steps below:

  1. Open an account with IB
  2. Download the IB Python TWS API
  3. Download the IB client (TWS or IB Gateway) Trader Workstation Platform
  4. Test for connectivity – Check code sample below

Installation

Create a local python virtual environment:

python3 -m venv ./env

Activate the environment, all the following packages will be install in the local ./env directory

source ./env/bin/activate

Install backtrader locally (see Installing Backtrader for more options)

pip install backtrader

Download Interactive Brokers TWS API (from Trader Workstation API)

Select the latest copy, currently it is (twsapi_macunix.1016.01.zip) for Linux

unzip twsapi_macunix.1016.01.zip

The file will unzip to the directoty IBJts

cd IBJts/source/pythonclient

Run the setup.py to install the TWS API.

python setup.py install

Download a Atreyu Backtrader API, released version:

wget https://github.com/atreyuxtrading/atreyu-backtrader-api/archive/refs/tags/v1.0.zip

Unzip file, and install the Atreyu Backtrader API.

unzip v1.0.zip

cd atreyu-backtrader-api-1.0 ; python setup.py install

Check Settings of Locally Running TWS

TWS Settings

Example: Download Realtime Bar Data from TWS

import backtrader as bt
from atreyu_backtrader_api import IBData

cerebro = bt.Cerebro()

data = IBData(host='127.0.0.1', port=7497, clientId=35,
               name="GOOG",     # Data name
               dataname='GOOG', # Symbol name
               secType='STK',   # SecurityType is STOCK 
               exchange='SMART',# Trading exchange IB's SMART exchange 
               currency='USD',  # Currency of SecurityType
               rtbar=True,      # Request Realtime bars
               _debug=True      # Set to True to print out debug messagess from IB TWS API
              )

cerebro.adddata(data)
cerebro.run()

Create A TestPrinter

Note that this is created as a stratgey and will print all the bars that it receives

import backtrader as bt

class TestPrinter(bt.Strategy):

    def log(self, txt, dt=None):
        ''' Logging function for this strategy'''
        dt = dt or self.datas[0].datetime.datetime(0)
        print(f'{dt}, {txt}')

    def __init__(self):
        self.open = self.datas[0].open
        self.high = self.datas[0].high
        self.low = self.datas[0].low
        self.close = self.datas[0].close
        self.volume = self.datas[0].volume
        self.openinterest = self.datas[0].openinterest

    def next(self):
        self.log(f'Open:{self.open[0]:.2f}, \
                   High:{self.high[0]:.2f}, \
                   Low:{self.low[0]:.2f}, \
                   Close:{self.close[0]:.2f}, \
                   Volume:{self.volume[0]:.2f}, \
                   OpenInterest:{self.volume[0]:.2f}' )
        

Simple BID_ASK Historical Data

import backtrader as bt

from atreyu_backtrader_api import IBData
from test_printer import TestPrinter

import datetime as dt

cerebro = bt.Cerebro()

data = IBData(host='127.0.0.1', port=7497, clientId=35,
               name="GOOG",     # Data name
               dataname='GOOG', # Symbol name
               secType='STK',   # SecurityType is STOCK 
               exchange='SMART',# Trading exchange IB's SMART exchange 
               currency='USD',  # Currency of SecurityType
               historical=True,
               what='BID_ASK',  # Update this parameter to select data type
              )

cerebro.adddata(data)

# Add the printer as a strategy
cerebro.addstrategy(TestPrinter)

cerebro.run()

Output

2021-08-09 23:59:59.999986, Open:137.24, High:144.44, Low:136.25, Close:137.55, Volume:-1.00
2021-08-10 23:59:59.999986, Open:138.02, High:139.84, Low:125.00, Close:138.26, Volume:-1.00
2021-08-11 23:59:59.999986, Open:137.54, High:138.95, Low:130.66, Close:137.89, Volume:-1.00
2021-08-12 23:59:59.999986, Open:137.82, High:139.07, Low:130.00, Close:138.12, Volume:-1.00
2021-08-13 23:59:59.999986, Open:138.23, High:139.09, Low:137.78, Close:138.52, Volume:-1.00
2021-08-16 23:59:59.999986, Open:138.04, High:139.90, Low:125.00, Close:138.34, Volume:-1.00
....
2022-08-05 23:59:59.999986, Open:118.06, High:128.00, Low:111.06, Close:118.19, Volume:-1.00
2022-08-07 20:00:00, Open:118.93, High:120.88, Low:113.00, Close:119.02, Volume:-1.00

Select Historical Data Types Using "what=" Parameter

Historical data is returned in the form of candlesticks, and accessed using the “what=” parameter when requesting data. (see Interactive Brokers Data Types) What Data Types

Fetch what=TRADES between 2016/01/01 - 2018/01/01

import backtrader as bt

from atreyu_backtrader_api import IBData
from test_printer import TestPrinter

import datetime as dt

cerebro = bt.Cerebro()

data = IBData(host='127.0.0.1', port=7497, clientId=35,
               name="GOOG",     # Data name
               dataname='GOOG', # Symbol name
               secType='STK',   # SecurityType is STOCK 
               exchange='SMART',# Trading exchange IB's SMART exchange 
               currency='USD',  # Currency of SecurityType
               fromdate = dt.datetime(2016, 1, 1),
               todate = dt.datetime(2018, 1, 1),
               historical=True,
               what='TRADES',
              )

cerebro.adddata(data)

# Add the printer as a strategy
cerebro.addstrategy(TestPrinter)

cerebro.run()

Output

2016-01-05 00:00:00, Open:37.38, High:37.38, Low:36.56, Close:37.10, Volume:460493.60
2016-01-06 00:00:00, Open:37.00, High:37.60, Low:36.93, Close:37.15, Volume:272008.00
2016-01-07 00:00:00, Open:36.87, High:37.36, Low:36.25, Close:37.30, Volume:276044.20
2016-01-08 00:00:00, Open:36.17, High:36.92, Low:35.95, Close:36.50, Volume:425276.00
...
2017-12-27 00:00:00, Open:52.86, High:53.00, Low:52.51, Close:52.70, Volume:70263.00
2017-12-28 00:00:00, Open:52.90, High:52.92, Low:52.40, Close:52.46, Volume:151108.40
2017-12-29 00:00:00, Open:52.66, High:52.74, Low:52.24, Close:52.36, Volume:105796.60
2017-12-30 00:00:00, Open:52.42, High:52.55, Low:52.13, Close:52.24, Volume:75590.60

How is the Data Presented in the Strategy?

The data retrieved from IB is presented in the strategy as the variable self.datas[0].

The latest close price is available at index 0, and progressively earlier prices are stored using a negative index. (See diagram below)

Data Layout

import backtrader as bt

# Create a Stratey
class TestStrategy(bt.Strategy):

    def log(self, txt, ts=None):
        ''' Logging function for this strategy'''
        ts = ts or self.datas[0].datetime.datetime(0)
        print(f'{ts}, {txt}')

    def __init__(self):
        self.close = self.datas[0].close

    def next(self):
        # Current close
        self.log(f'Close:{self.close[0]:.2f}' )
        if self.close[0] < self.close[-1]:
             # current close less than previous close, think about buying
             if self.close[-1] < self.close[-2]:
                # previous close less than previous close, so buy
                self.log('BUY CREATE, %.2f' % self.close[0])
                self.buy()

Using IB Historical Data to Drive a Strategy with "what=MIDPOINT"

import backtrader as bt

from atreyu_backtrader_api import IBData
from test_strategy import TestStrategy

import datetime as dt

cerebro = bt.Cerebro()

data = IBData(host='127.0.0.1', port=7497, clientId=35,
               name="GOOG",     # Data name
               dataname='GOOG', # Symbol name
               secType='STK',   # SecurityType is STOCK 
               exchange='SMART',# Trading exchange IB's SMART exchange 
               currency='USD',  # Currency of SecurityType
               fromdate = dt.datetime(2016, 1, 1),
               todate = dt.datetime(2018, 1, 1),
               historical=True,
               what='MIDPOINT',
              )

cerebro.adddata(data)

# Add the test strategy
cerebro.addstrategy(TestStrategy)

# Set our desired cash start
cerebro.broker.setcash(100000.0)

cerebro.run()

print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

Naming Datasources and using them in a Strategy

Datasources can be given logical datanames (i.e. based on the "what" parameter), the logical name can then be accessed using the _name variable. In the strategy below the logical name is stored in the self.name0 and self.name1 variables, and can be used to identify the buy for each symbol.

import backtrader as bt

# Create a Stratey
class TestStrategy(bt.Strategy):

    def log(self, txt, ts=None):
        ''' Logging function for this strategy'''
        ts = ts or self.datas[0].datetime.datetime(0)
        print(f'{ts}, {txt}')

    def __init__(self):
        self.close0 = self.datas[0].close
        self.name0 = self.datas[0]._name

        self.close1 = self.datas[1].close
        self.name1 = self.datas[1]._name

    def next(self):
        # Current close dataset0
        self.log(f'{self.name0} Close:{self.close0[0]:.2f}' )
        if self.close0[0] < self.close0[-1]:
             # current close less than previous close, think about buying
             if self.close0[-1] < self.close0[-2]:
                # previous close less than previous close, so buy
                self.log(f"BUY {self.name0} @ {self.close0[0]:.2f}")
                self.buy()

        # Current close dataset1
        self.log(f'{self.name1} Close:{self.close1[0]:.2f}' )
        if self.close1[0] < self.close1[-1]:
             # current close less than previous close, think about buying
             if self.close1[-1] < self.close1[-2]:
                # previous close less than previous close, so buy
                self.log(f"BUY {self.name1} @ {self.close1[0]:.2f}")
                self.buy()

See the name parameter being used to tag each datasource in the example below:

import backtrader as bt

from atreyu_backtrader_api import IBData
from test_strategy import TestStrategy

import datetime as dt

cerebro = bt.Cerebro()

goog_data = IBData(host='127.0.0.1', port=7497, clientId=35,
               name="GOOG_TRADES",  # Data name
               dataname='GOOG',     # Symbol name
               secType='STK',       # SecurityType is STOCK 
               exchange='SMART',    # Trading exchange IB's SMART exchange 
               currency='USD',      # Currency of SecurityType
               fromdate = dt.datetime(2016, 1, 1),
               todate = dt.datetime(2018, 1, 1),
               historical=True,
               what='TRADES',
              )

cerebro.adddata(goog_data)

apple_data = IBData(host='127.0.0.1', port=7497, clientId=35,
               name="AAPL_MIDPOINT",# Data name
               dataname='AAPL',     # Symbol name
               secType='STK',       # SecurityType is STOCK 
               exchange='SMART',    # Trading exchange IB's SMART exchange 
               currency='USD',      # Currency of SecurityType
               fromdate = dt.datetime(2016, 1, 1),
               todate = dt.datetime(2018, 1, 1),
               historical=True,
               what='MIDPOINT',
              )

cerebro.adddata(apple_data)

# Add the test strategy
cerebro.addstrategy(TestStrategy)

# Set our desired cash start
cerebro.broker.setcash(100000.0)

cerebro.run()

print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())

Output

2016-01-05 00:00:00, AAPL_MIDPOINT Close:26.43
2016-01-05 00:00:00, BUY AAPL_MIDPOINT @ 26.43
2016-01-05 00:00:00, GOOG_TRADES Close:37.10
2016-01-05 00:00:00, BUY GOOG_TRADES @ 37.10
...
2017-12-29 00:00:00, AAPL_MIDPOINT Close:42.71
2017-12-30 00:00:00, GOOG_TRADES Close:52.24
2017-12-30 00:00:00, BUY GOOG_TRADES @ 52.24
2017-12-30 00:00:00, AAPL_MIDPOINT Close:42.27
Final Portfolio Value: 102168.92

5-Second Real-time Bars from IB

Real-time bars represent a price performance for a specific period. These periods could be as long as a day or as short as a second, depending on the purpose for which the bar is to be used. Daily bars are usually the most popular for analysis whereas shorter duration bars can be used for trading.

In the case of IB the TWS API can be used to fetch 5-second duration bar. The example below creates an active subscription that will return a single bar in real time every five seconds that has the OHLC values over that period. Additionally we are switching off the backfill of data from initial start to reconnect in case of connection disruption.

import backtrader as bt

from atreyu_backtrader_api import IBData
from test_printer import TestPrinter

import datetime as dt
from datetime import datetime, date, time

cerebro = bt.Cerebro()

data = IBData(host='127.0.0.1', port=7497, clientId=35,
               name="AAPL",  # Data name
               dataname='AAPL',     # Symbol name
               secType='STK',       # SecurityType is STOCK 
               exchange='SMART',    # Trading exchange IB's SMART exchange 
               currency='USD',      # Currency of SecurityType
               backfill_start=False,
               backfill=False,
               what='TRADES', # TRADES or MIDPOINT
               rtbar=True
              )

cerebro.adddata(data)

# Add the test strategy
cerebro.addstrategy(TestPrinter)

cerebro.run()

Output

2022-08-11 15:22:20, Symbol: AAPL Open:169.29, High:169.29, Low:169.28, Close:169.29, Volume:101.13
2022-08-11 15:22:25, Symbol: AAPL Open:169.29, High:169.29, Low:169.25, Close:169.26, Volume:79.5
2022-08-11 15:22:30, Symbol: AAPL Open:169.27, High:169.30, Low:169.23, Close:169.23, Volume:57.5
2022-08-11 15:22:35, Symbol: AAPL Open:169.23, High:169.30, Low:169.22, Close:169.27, Volume:89.72

Top Of Book Market Data (Level I)

Using the TWS API, real time market data can also be requested for trading and analysis. This data is not tick-by-tick but consists of aggregated snapshots taken at intra-second intervals which differ depending on the type of instrument:

Product Frequency

We select non-bar data by setting rtbar=False, note that the data will still be presented in the OHLCV format for use in the strategy.

import backtrader as bt

from atreyu_backtrader_api import IBData
from test_printer import TestPrinter

import datetime as dt
from datetime import datetime, date, time

cerebro = bt.Cerebro()

data = IBData(host='127.0.0.1', port=7497, clientId=35,
               name="AAPL",  # Data name
               dataname='AAPL',     # Symbol name
               secType='STK',       # SecurityType is STOCK 
               exchange='SMART',    # Trading exchange IB's SMART exchange 
               currency='USD',      # Currency of SecurityType
               backfill_start=False,
               backfill=False,
               rtbar=False
              )

cerebro.adddata(data)

# Add the test strategy
cerebro.addstrategy(TestPrinter)

cerebro.run()

Ouput

2022-08-11 16:36:11.410065, Symbol: AAPL Open:169.70, High:169.70, Low:169.70, Close:169.70, Volume:2200.0
2022-08-11 16:36:11.410105, Symbol: AAPL Open:169.70, High:169.70, Low:169.70, Close:169.70, Volume:100.0
2022-08-11 16:36:11.410156, Symbol: AAPL Open:169.70, High:169.70, Low:169.70, Close:169.70, Volume:100.0
2022-08-11 16:36:11.410196, Symbol: AAPL Open:169.70, High:169.70, Low:169.70, Close:169.70, Volume:253852.0
2022-08-11 16:36:11.411061, Symbol: AAPL Open:169.69, High:169.69, Low:169.69, Close:169.69, Volume:253852.0
2022-08-11 16:36:11.411081, Symbol: AAPL Open:169.69, High:169.69, Low:169.69, Close:169.69, Volume:1900.0
2022-08-11 16:36:11.411141, Symbol: AAPL Open:169.71, High:169.71, Low:169.71, Close:169.71, Volume:1900.0
2022-08-11 16:36:11.411161, Symbol: AAPL Open:169.71, High:169.71, Low:169.71, Close:169.71, Volume:2900.0

Real-time Tick by Tick Data

In addition to the aggregated tick snapshots, IB also has true tick-by-tick data, but it comes with some limitations. Tick-by-tick data corresponds to the data shown in the TWS Time & Sales. The maximum number of simultaneous tick-by-tick subscriptions allowed for a user is determined by the limitations below.

Limitations - Additional symbol request can be purchased through a quote booster pack, each quote booster pack provides a 100 market data lines. There is a limit of 10 quote boosters packs per account and rest of the market data lines are allocated using equity and commissions.

Lines Requests

The “what=” must be set to the following BID_ASK (BidAsk), TRADES (Last), TRADES_ALL (AllLast), MIDPOINT (MidPoint), the default is TRADES if “what” is not set. TRADES_ALL has additional trade types such as combos, derivatives, and average price trades that are not included in TRADES. Note in the example below “timeframe=bt.TimeFrame.Ticks” to select the tick-by-tick IB function.

import backtrader as bt

from atreyu_backtrader_api import IBData
from test_printer import TestPrinter

import datetime as dt
from datetime import datetime, date, time

cerebro = bt.Cerebro()

data = IBData(host='127.0.0.1', port=7497, clientId=35,
               name="AAPL",  # Data name
               dataname='AAPL',     # Symbol name
               secType='STK',       # SecurityType is STOCK 
               exchange='SMART',    # Trading exchange IB's SMART exchange 
               currency='USD',      # Currency of SecurityType
               timeframe=bt.TimeFrame.Ticks,
               what='BID_ASK',      # TRADES, TRADES_ALL, MID_POINT
               rtbar=False
              )

cerebro.adddata(data)

# Add the test strategy
cerebro.addstrategy(TestPrinter)

cerebro.run()

Output

2022-08-11 17:29:22, Symbol: AAPL Open:nan, High:nan, Low:nan, Close:169.41, Volume:260.0
2022-08-11 17:29:22, Symbol: AAPL Open:nan, High:nan, Low:nan, Close:169.41, Volume:100.0
2022-08-11 17:29:22, Symbol: AAPL Open:nan, High:nan, Low:nan, Close:169.41, Volume:100.0
...
2022-08-11 17:29:22, Symbol: AAPL Open:nan, High:nan, Low:nan, Close:169.41, Volume:100.0
2022-08-11 17:29:22, Symbol: AAPL Open:nan, High:nan, Low:nan, Close:169.41, Volume:100.0
2022-08-11 17:29:22, Symbol: AAPL Open:nan, High:nan, Low:nan, Close:169.41, Volume:100.0

From Back Test to Paper Trading

In this section we look at the steps in developing a simple strategy and back testing it with historical data from IB. Then modifying it to Paper Trader in the TWS frontend.

An Example of a Simple Buy/Sell Strategy - Not that in this strategy we generate Buy and Sell market orders related to a simple moving average calculation. This strategy has been adapted from (https://www.backtrader.com/docu/quickstart/quickstart) with minor updates.

import backtrader as bt

# Create a Stratey
class TestStrategy(bt.Strategy):
    params = (
        ('ma_period', 15),
    )

    def log(self, txt, ts=None):
        ''' Logging function for this strategy'''
        ts = ts or self.datas[0].datetime.datetime(0)
        print(f'{ts}, {txt}')

    def __init__(self):
        # Keep a reference to the "close" line in the data[0] dataseries
        self.dataclose = self.datas[0].close

        # To keep track of pending orders and buy price/commission
        self.order = None
        self.buyprice = None
        self.buycomm = None

        # Add a MovingAverageSimple indicator
        self.sma = bt.indicators.SimpleMovingAverage(self.datas[0], period=self.params.ma_period)

    def notify_order(self, order):
        if order.status in [order.Submitted, order.Accepted]:
            # Buy/Sell order submitted/accepted to/by broker - Nothing to do
            return

        # Check if an order has been completed
        # Attention: broker could reject order if not enough cash
        if order.status in [order.Completed]:
            if order.isbuy():
                self.log(
                    f'BUY EXECUTED, Price: {order.executed.price:.2f}, Cost: {order.executed.value:.2f}, Comm: {order.executed.comm:.2f}')

                self.buyprice = order.executed.price
                self.buycomm = order.executed.comm
            else:  # Sell
                self.log(f'SELL EXECUTED, Price: {order.executed.price:.2f}, Cost: {order.executed.value:.2f}, Comm: {order.executed.comm:.2f}')

            self.bar_executed = len(self)

        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log('Order Canceled/Margin/Rejected')

        self.order = None

    def notify_trade(self, trade):
        if not trade.isclosed:
            return

        self.log(f'OPERATION PROFIT, GROSS: {trade.pnl:.2f}, NET: {trade.pnlcomm:.2f}')

    def next(self):
        # Simply log the closing price of the series from the reference
        self.log(f'Close, {self.dataclose[0]:.2f}')

        # Check if an order is pending ... if yes, we cannot send a 2nd one
        if self.order:
            return

        # Check if we are in the market
        if not self.position:
            # Not yet ... we MIGHT BUY if ...
            if self.dataclose[0] > self.sma[0]:

                # BUY, BUY, BUY!!! (with all possible default parameters)
                self.log(f'BUY CREATE  @MKT: {self.dataclose[0]:.2f}')

                # Keep track of the created order to avoid a 2nd order
                self.order = self.buy()
                self.log(f'BUY CREATED Size: {self.order.size} @ MKT')

        else:
            if self.dataclose[0] < self.sma[0]:
                # SELL, SELL, SELL!!! (with all possible default parameters)
                self.log(f'SELL CREATE @ MKT: {self.dataclose[0]:.2f}')

                # Keep track of the created order to avoid a 2nd order
                self.order = self.sell()
                self.log(f'SELL CREATED Size: {self.order.size} @ MKT')

Back Testing The Strategy Using IB Historical Data

import backtrader as bt

from atreyu_backtrader_api import IBData
from test_strategy import TestStrategy

import datetime as dt
from datetime import datetime, date, time

cerebro = bt.Cerebro()

data = IBData(host='127.0.0.1', port=7497, clientId=35,
               name="AAPL",         # Data name
               dataname='AAPL',     # Symbol name
               secType='STK',       # SecurityType is STOCK
               exchange='SMART',    # Trading exchange IB's SMART exchange 
               currency='USD',      # Currency of SecurityType
               historical=True
              )

cerebro.adddata(data)

# Set our desired cash start
cerebro.broker.setcash(100000.0)

# Add the test strategy
cerebro.addstrategy(TestStrategy)

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

cerebro.run()

# Print out the final result
print(f'Final Portfolio Value: {cerebro.broker.getvalue():.2f}')

Output

2021-09-01 23:59:59.999989, Close, 153.16
2021-09-01 23:59:59.999989, BUY CREATE  @MKT: 153.16
2021-09-01 23:59:59.999989, BUY CREATED Size: 10 @ MKT
2021-09-02 23:59:59.999989, BUY EXECUTED, Price: 152.86, Cost: 1528.60, Comm: 0.00
2021-09-02 23:59:59.999989, Close, 153.59
2021-09-03 23:59:59.999989, Close, 154.29
2021-09-07 23:59:59.999989, Close, 156.76
2021-09-08 23:59:59.999989, Close, 155.00
2021-09-09 23:59:59.999989, Close, 154.27
2021-09-10 23:59:59.999989, Close, 148.67
2021-09-10 23:59:59.999989, SELL CREATE @ MKT: 148.67
2021-09-10 23:59:59.999989, SELL CREATED Size: -10 @ MKT
2021-09-13 23:59:59.999989, SELL EXECUTED, Price: 149.70, Cost: 1528.60, Comm: 0.00
2021-09-13 23:59:59.999989, OPERATION PROFIT, GROSS: -31.60, NET: -31.60
2021-09-13 23:59:59.999989, Close, 149.53
2021-09-14 23:59:59.999989, Close, 148.19
...
2022-08-08 23:59:59.999989, Close, 165.27
2022-08-09 23:59:59.999989, Close, 165.01
2022-08-10 23:59:59.999989, Close, 169.10
2022-08-11 00:00:00, Close, 168.89
Final Portfolio Value: 100409.00

Paper Trading on IB

Once a strategy has been back tested for basic operation it should be paper traded i.e. where simulated trades are generated and marked using live data to gain confidence in your overall trading strategy and goal.

Be careful to login to TWS using the Paper Trading option (see arrow): Paper Trading

In addition to selecting “Paper Trading” the execution of the strategy also needs to be changed to use IB as the broker to place orders and update positions.

import backtrader as bt

from atreyu_backtrader_api import IBData
from atreyu_backtrader_api import IBStore

from test_strategy import TestStrategy

import datetime as dt
from datetime import datetime, date, time

cerebro = bt.Cerebro()

ibstore = IBStore(host='127.0.0.1', 
                  port=7497, 
                  clientId=35)

data = ibstore.getdata(name="AAPL",         # Data name
                       dataname='AAPL',     # Symbol name
                       secType='STK',       # SecurityType is STOCK
                       exchange='SMART',    # Trading exchange IB's SMART exchange 
                       currency='USD'      # Currency of SecurityType
                       )

cerebro.adddata(data)

broker = ibstore.getbroker()

# Set the broker
cerebro.setbroker(broker)

# Add the test strategy
cerebro.addstrategy(TestStrategy)

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

cerebro.run()

Output

...
2022-08-17 19:06:33.352691, Close, 174.84
2022-08-17 19:06:33.352741, Close, 174.84
2022-08-17 19:06:33.352781, Close, 174.84
2022-08-17 19:06:33.601432, SELL EXECUTED, Price: 174.83, Cost: 1749.40, Comm: 1.04
2022-08-17 19:06:33.601432, OPERATION PROFIT, GROSS: -0.10, NET: -2.14
2022-08-17 19:06:33.601432, Close, 174.83
2022-08-17 19:06:33.601462, Close, 174.83
2022-08-17 19:06:33.601522, Close, 174.85
2022-08-17 19:06:33.601522, BUY CREATE  @MKT: 174.85
2022-08-17 19:06:33.601522, BUY CREATED Size: 10 @ MKT
2022-08-17 19:06:33.601533, Close, 174.85
...

Once the strategy is initiated the orders start appearing in TWS

Main Trading

From Paper Trading To Real Trading – Monitoring, Debug and Go Live!

Paper trading can help to validate the efficacy of a strategy, so it is prudent to continue paper trading until a stable performance and profitability profile has been achieved.

Sometimes successful paper trading strategies may not translate to the same performance in real trading. This can be for a myriad of reasons from external factors (market impact, price slippage, market microstructure etc.) to simple programming issues.

To help isolate and identify these issues it is important to have a robust monitoring and debugging facilities built into the trading process.

The simplest and most effective function is having accurate logging that records not only the trades but identifies the assets, opening and closing prices and trigger conditions and parameters pertinent to the strategy. Additionally the Backtrader and TWS API also has debugging built and can be accessed by setting the appropriate configuration parameters.

TWS Ports

An Example of a Simple Buy/Sell Strategy With Logging

import backtrader as bt

import logging
# Generate file level logger
logger = logging.getLogger(__name__)

# Create a Stratey
class TestStrategy(bt.Strategy):
    params = (
        ('ma_period', 15),
    )

    def log(self, txt, ts=None):
        ''' Logging function for this strategy'''
        # Add log statement
        logger.info(f'{txt}')
        ...
        

Setting Up A Log File

There is a example custom logger supplied in the atreyu_backtrader_api module, and can be referenced in the code as follows:

import logging
from atreyu_backtrader_api.custom_logger import setup_custom_logger

The logger has the following properties:

  • It can write a named log file into a named directory thereby keeping all the logs together.
  • It has log rotation, e.g. it does not overwrite logs on repeated restarts but backs each log keeping the specified logfile as the latest log.
  • Each log line can be echoed to the terminal as well as written to the logfile

The logger can be setup as follows:

LOGGING_DEBUG = False
logger = setup_custom_logger(global_name = 'root',
                              debug_level = logging.DEBUG if LOGGING_DEBUG else logging.INFO,
                              filename    = "sma_strategy.log", # Set the log file name
                              logdirname  = './logs',           # and the directory for the logs
                              console     = True)               # Echo the log line to the terminal

Configuring each sub-logger for the module and source file that is of interest, can control the logfile output.

LOGGING_DEBUG = False
logger = setup_custom_logger(global_name = 'root',
                              debug_level = logging.DEBUG if LOGGING_DEBUG else logging.INFO,
                              filename    = "sma_strategy.log", # Set the log file name
                              logdirname  = './logs',           # and the directory for the logs
                              console     = True)               # Echo the log line to the terminal

# Log configuration for Atreyu Back Trader API module
logging.getLogger('atreyu_backtrader_api').setLevel(logging.ERROR)
# logging.getLogger('atreyu_backtrader_api.ibbroker').setLevel(logging.INFO)
# logging.getLogger('atreyu_backtrader_api.ibdata').setLevel(logging.INFO)
# logging.getLogger('atreyu_backtrader_api.ibstore').setLevel(logging.INFO)

# Log configuration for IB API module
logging.getLogger('ibapi').setLevel(logging.ERROR)
# logging.getLogger('ibapi.decoder').setLevel(logging.ERROR)
# logging.getLogger('ibapi.utils').setLevel(logging.ERROR)
# logging.getLogger('ibapi.client').setLevel(logging.ERROR)
#logging.getLogger('ibapi.decoder').setLevel(logging.DEBUG)

Enable Logging in Backtrader To enable logging in the Backtrader framework the _debug = True variable can be passed when setting up the IBStore and IBData classes.

PAPER_TRADING_PORT = 7497
LIVE_TRADING_PORT = 7496

cerebro = bt.Cerebro()
HOST = '127.0.0.1'
PORT = PAPER_TRADING_PORT
logger.info(f"Starting host: {HOST} port: {PORT}")
ibstore = IBStore(host=HOST, 
                  port=PORT, 
                  clientId=35,
                  _debug = True)

data = ibstore.getdata(name="AAPL",         # Data name
                       dataname='AAPL',     # Symbol name
                       secType='STK',       # SecurityType is STOCK
                       exchange='SMART',    # Trading exchange IB's SMART exchange 
                       currency='USD',       # Currency of SecurityType
                       _debug = True
                       )

cerebro.adddata(data)

broker = ibstore.getbroker()

# Set the broker
cerebro.setbroker(broker)

Output

Calling updateAccountTime('20:10')
Calling tickSize(16777217, 8, Decimal('361198'))
Calling tickString(16777217, 45, '1661454621')
Calling tickString(16777217, 84, 'Z')
Calling tickPrice(16777217, 4, 169.19, 4361192208: CanAutoExecute: 0, PastLimit: 0, PreOpen: 0)
Calling tickSize(16777217, 5, Decimal('100'))
Calling tickSize(16777217, 5, Decimal('100'))
Calling tickPrice(16777217, 1, 169.18, 4361192208: CanAutoExecute: 1, PastLimit: 0, PreOpen: 0)
Calling tickSize(16777217, 0, Decimal('1600'))
Calling get_acc_cash()
Calling tickPrice(16777217, 2, 169.19, 4361192448: CanAutoExecute: 1, PastLimit: 0, PreOpen: 0)
Calling get_acc_value()
Calling tickSize(16777217, 3, Decimal('1500'))
Calling get_acc_value()
Calling tickSize(16777217, 0, Decimal('1600'))
Calling tickSize(16777217, 3, Decimal('1500'))
Calling tickString(16777217, 32, 'PQXZUH')
Calling tickString(16777217, 33, 'KPQZNUH')

Onward To Live Trading

Now that you have implemented logging, and have and good understanding of how to debug your strategy you are ready to go live.

It is suggested that trading starts small, and that as confidence is gained trading sizes/frequency is increased within your prescribed risk appetite. At each stage it is recommended that you review the logs for anomalies that you may not notice from looking at the TWS screens.

Switching the strategy to live trading is as simple as logging in with TWS for trading and changing the port designator in the code below:

PAPER_TRADING_PORT = 7497
LIVE_TRADING_PORT = 7496

cerebro = bt.Cerebro()
HOST = '127.0.0.1'
PORT = LIVE_TRADING_PORT
logger.info(f"Starting host: {HOST} port: {PORT}")
ibstore = IBStore(host=HOST, 
                  port=PORT, 
                  clientId=35,
                  _debug = True)

data = ibstore.getdata(name="AAPL",         # Data name
                       dataname='AAPL',     # Symbol name
                       secType='STK',       # SecurityType is STOCK
                       exchange='SMART',    # Trading exchange IB's SMART exchange 
                       currency='USD',       # Currency of SecurityType
                       _debug = True
                       )

cerebro.adddata(data)

broker = ibstore.getbroker()

# Set the broker
cerebro.setbroker(broker)

Disclaimer

The software is provided on the conditions of the simplified BSD license.

This project is not affiliated with Interactive Brokers Group, Inc.

atreyu-backtrader-api's People

Contributors

atreyuxtrading avatar jorgydev avatar

Stargazers

 avatar  avatar Tiago Pina Contini avatar Zahav Capper avatar Chrysus avatar Regular trihedron avatar  avatar Yesen Muu avatar thudra avatar Alexandre See avatar adamada avatar  avatar  avatar ilove0518 avatar Shashank Pallerla avatar fred monroe avatar Jinchao avatar Vlad Dovlekaev avatar Ethan avatar Joshua Schmidt avatar Joseph Luce avatar Vincent Pisano avatar  avatar  avatar  avatar  avatar Bosh Ng avatar Peter Roosakos avatar  avatar Yang Minxing avatar Allen Zhang avatar Georg avatar Thomas avatar EdenN0 avatar Fabio Ferrari avatar AlgoEng avatar Anton M. avatar CharlesXu avatar  avatar Jothimurugan Muthusamy avatar  avatar  avatar Siou avatar  avatar  avatar  avatar  avatar Yuanpu Xie avatar  avatar  avatar Valter Levander avatar  avatar  avatar  avatar  avatar  avatar Andrej avatar  avatar  avatar Phi avatar  avatar Mani Chandra avatar  avatar Joshua Ardito avatar  avatar Yuan Huang avatar Victor Hugo Barros avatar Sherrill avatar  avatar Joey-Lee avatar  avatar  avatar  avatar Galip Usta avatar CapsulE avatar Franco S avatar Spyros Angelis avatar  avatar Sonami avatar  avatar WebClinic avatar zgpnuaa avatar  avatar

Watchers

 avatar  avatar Vincent Pisano avatar  avatar  avatar ElliottLabs avatar

atreyu-backtrader-api's Issues

Reconnect on IB Gateway/TWS auto restart

As we all known, TWS/IBG restarts everyday, now, on the latest versions the session token lasts for a week so you don't have to enter username/password. What I am struggling to make it work, on the restart, is the live data when the IB Gateway restarts.

Looking at the code, the msg=-504 is well recognized, however, there is no way to resuscribe to the live data feed. Tried many things but there is no way to take it back.

Thanks

' time-zone entered is invalid' error

Hi,

I am following this tutorial to simply try to print some live data from TWS

As result I get the following error

Error: {'reqId': 16777217, 'errorCode': 10314, 'errorString': 'End Date/Time: The date, time, or time-zone entered is invalid. The correct format is yyyymmdd hh:mm:ss xx/xxxx where yyyymmdd and xx/xxxx are optional. E.g.: 20031126 15:59:00 US/Eastern Note that there is a space between the date and time, and between the time and time-zone. If no date is specified, current date is assumed. If no time-zone is specified, local time-zone is assumed(deprecated). You can also provide yyyymmddd-hh:mm:ss time is in UTC. Note that there is a dash between the date and time in UTC notation.', 'advancedOrderRejectJson': ''}

Is there a way to overcome it? Look's like requests need a different time zone specification as discussed here

What would be the simplest way to solve this issue?

Thanks

Bracket/oco functionality doesn't work with IB

File ~/anaconda3/lib/python3.9/site-packages/atreyu_backtrader_api-0.1.0-py3.9.egg/atreyu_backtrader_api/ibbroker.py:358 in submit
order.ocaGroup = self.orderbyid[order.oco.orderId].ocaGroup

AttributeError: 'int' object has no attribute 'orderId'

Exception: 'Execution' object has no attribute 'OrderId'
Traceback (most recent call last):
File "/home/tim/anaconda3/lib/python3.9/site-packages/atreyu_backtrader_api-0.1.0-py3.9.egg/atreyu_backtrader_api/ibbroker.py", line 520, in push_commissionreport
oid = ex.OrderId
AttributeError: 'Execution' object has no attribute 'OrderId'
ExecId: 0000e1a7.641848b4.01.01, Commission: 0.770000, Currency: USD, RealizedPnL: , Yield: , YieldRedemptionDate: 0

End Date/Time Error on Historical Quote

Also having a problem with the historical quote example. In this case:

data = IBData(host='127.0.0.1', port=7497, clientId=35,
               name="GOOG",     # Data name
               dataname='GOOG', # Symbol name
               secType='STK',   # SecurityType is STOCK 
               exchange='SMART',# Trading exchange IB's SMART exchange 
               currency='USD',  # Currency of SecurityType
               historical=True,
               what='BID_ASK',  # Update this parameter to select data type
              )

Is returning the following error on execution:

Error: {'reqId': 16777217, 'errorCode': 10314, 'errorString': 'End Date/Time: The date, time, or time-zone entered is invalid. The correct format is yyyymmdd hh:mm:ss xx/xxx where yyyymmdd and xx/xxx are optional. E.g.: 20031126 15:59:00 US/Eastern Note that there is a space between the date and time, and between the time and time-zone. If no date is specified, current date is assumed. If no time-zone is specified, local time-zone is assumed(deprecated). You can also provide yyyymmddd-hh:mm:ss time is in UTC. Note that there is a dash between the date and time in UTC notation.', 'advancedOrderRejectJson': ''}

321 Error With Simple Quote Example

I'm just getting things up and running here - but it seems like maybe the example code is out of date?

After setting up the environment and testing my connections, executing a python script with the following IBData object:

data = IBData(host='127.0.0.1', port=7497, clientId=35,
               name="GOOG",     # Data name
               dataname='GOOG', # Symbol name
               secType='STK',   # SecurityType is STOCK 
               exchange='SMART',# Trading exchange IB's SMART exchange 
               currency='USD',  # Currency of SecurityType
               what='BID_ASK',  # Get data fields (see note below)
               rtbar=True,      # Request Realtime bars
               _debug=True      # Set to True to print out debug messagess from IB TWS API
              )

Results in a stream of 321 errors from the TWS API Client complaining about the 'What to show field':


Calling reqRealTimeBars(4557295888: 208813720,GOOG,STK,,0,,,SMART,NASDAQ,USD,GOOG,NMS,False,,,,combo:, what='BID_ASK')
Calling error(16780436, 321, "Error validating request.-'bY' : cause - What to show field is missing or incorrect.", '')
{'reqId': 16780436, 'errorCode': 321, 'errorString': "Error validating request.-'bY' : cause - What to show field is missing or incorrect.", 'advancedOrderRejectJson': ''}
Error: {'reqId': 16780436, 'errorCode': 321, 'errorString': "Error validating request.-'bY' : cause - What to show field is missing or incorrect.", 'advancedOrderRejectJson': ''}
Cancel data queue for 16780436

Should the 'what' field maybe be 'TRADES' instead of 'BID_ASK'?

Adding more than one data (=Symbol) doesn't work for me

Hey Atreyu trading,

Great library, thanks for integrating with original TWS API. Very clean code. However, there still seems to be a glitch with threading. Running the sample from the readme that has more than one symbol doesn't work for me. If first data is GOOG, then it retrieves a batch with Google historical data, as I can see with debug set to True, but then hangs and never gets the response for the AAPL request. If change the order in the code, then I get the AAPL data, but no GOOG data.

Thanks
Reinke

Below is the output in debug mode from your example (I ran it with AMZN instead of AAPL, but result is the same):
Calling connectAck()
Calling managedAccounts('DUXXXXXX')
Calling reqCurrentTime()
Calling nextValidId(1)
Calling error(-1, 2104, 'Market data farm connection is OK:hfarm')
Calling error(-1, 2104, 'Market data farm connection is OK:eufarmnj')
Calling error(-1, 2104, 'Market data farm connection is OK:cashfarm')
Calling error(-1, 2104, 'Market data farm connection is OK:usfuture')
Calling error(-1, 2104, 'Market data farm connection is OK:jfarm')
Calling error(-1, 2104, 'Market data farm connection is OK:usfarm.nj')
Calling error(-1, 2104, 'Market data farm connection is OK:eufarm')
Calling error(-1, 2104, 'Market data farm connection is OK:usfarm')
Calling error(-1, 2106, 'HMDS data farm connection is OK:euhmds')
Calling error(-1, 2106, 'HMDS data farm connection is OK:ushmds.nj')
Calling error(-1, 2106, 'HMDS data farm connection is OK:cashhmds')
Calling error(-1, 2106, 'HMDS data farm connection is OK:fundfarm')
Calling error(-1, 2106, 'HMDS data farm connection is OK:ushmds')
Calling error(-1, 2158, 'Sec-def data farm connection is OK:secdefnj')
Calling currentTime(1663164990)
Calling contractDetails(16777216, 140192311566224: 3691937,AMZN,STK,,0.0,,,SMART,NASDAQ,USD,AMZN,NMS,False,,combo:,NMS,0.01,ACTIVETIM,AD,ADJUST,ALERT,ALGO,ALLOC,AON,AVGCOST,BASKET,BENCHPX,CASHQTY,COND,CONDORDER,DARKONLY,DARKPOLL,DAY,DEACT,DEACTDIS,DEACTEOD,DIS,DUR,GAT,GTC,GTD,GTT,HID,IBKRATS,ICE,IMB,IOC,LIT,LMT,LOC,MIDPX,MIT,MKT,MOC,MTL,NGCOMB,NODARK,NONALGO,OCA,OPG,OPGREROUT,PEGBENCH,PEGMID,POSTATS,POSTONLY,PREOPGRTH,PRICECHK,REL,REL2MID,RELPCTOFS,RPI,RTH,SCALE,SCALEODD,SCALERST,SIZECHK,SMARTSTG,SNAPMID,SNAPMKT,SNAPREL,STP,STPLMT,SWEEP,TRAIL,TRAILLIT,TRAILLMT,TRAILMIT,WHATIF,SMART,AMEX,NYSE,CBOE,PHLX,ISE,CHX,ARCA,ISLAND,DRCTEDGE,BEX,BATS,EDGEA,CSFBALGO,JEFFALGO,BYX,IEX,EDGX,FOXRIVER,PEARL,NYSENAT,LTSE,MEMX,TPLUS1,PSX,1,0,AMAZON.COM INC,,Communications,Internet,E-Commerce/Products,US/Eastern,20220914:0400-20220914:2000;20220915:0400-20220915:2000;20220916:0400-20220916:2000;20220917:CLOSED;20220918:CLOSED;20220919:0400-20220919:2000,20220914:0930-20220914:1600;20220915:0930-20220915:1600;20220916:0930-20220916:1600;20220917:CLOSED;20220918:CLOSED;20220919:0930-20220919:1600,,0,100,,,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,1,[140192311564448: ISIN=US0231351067;],,COMMON,,,,,,False,False,0,False,,,,,False,)
Calling contractDetailsEnd(16777216)
Calling reqHistoricalDataEx(contract=140192311564496: 3691937,AMZN,STK,,0.0,,,SMART,NASDAQ,USD,AMZN,NMS,False,,combo:, enddate=datetime.datetime(2018, 5, 1, 0, 0), begindate=datetime.datetime(2018, 1, 1, 0, 0), timeframe=5, compression=1, what='TRADES', useRTH=False, tz=None, sessionend=datetime.time(23, 59, 59, 999990))
Calling historicalData(16777217, 140192311562864: Date: 20180102, Open: 58.390000, High: 59.500000, Low: 58.390000, Close: 59.300000, Volume: 362006, Average: 59.214400, BarCount: 10587)
Calling historicalData(16777217, 140192310323872: Date: 20180103, Open: 59.440000, High: 60.270000, Low: 59.330000, Close: 60.150000, Volume: 428208, Average: 59.995700, BarCount: 13522)
Calling historicalData(16777217, 140192310323440: Date: 20180104, Open: 60.400000, High: 60.790000, Low: 60.230000, Close: 60.510000, Volume: 415628, Average: 60.504250, BarCount: 12929)
Calling historicalData(16777217, 140192310324208: Date: 20180105, Open: 60.550000, High: 61.560000, Low: 60.500000, Close: 61.530000, Volume: 482647, Average: 61.088200, BarCount: 14759)
Calling historicalData(16777217, 140192310324064: Date: 20180108, Open: 61.670000, High: 62.650000, Low: 61.500000, Close: 62.360000, Volume: 558346, Average: 62.216000, BarCount: 17556)
Calling historicalData(16777217, 140192310323488: Date: 20180109, Open: 62.410000, High: 62.970000, Low: 62.090000, Close: 62.640000, Volume: 520424, Average: 62.540200, BarCount: 15995)
Calling historicalData(16777217, 140192310324784: Date: 20180110, Open: 62.500000, High: 62.800000, Low: 61.860000, Close: 62.800000, Volume: 379151, Average: 62.417450, BarCount: 11669)
Calling historicalData(16777217, 140192310324352: Date: 20180111, Open: 62.850000, High: 63.900000, Low: 62.820000, Close: 63.890000, Volume: 446149, Average: 63.307650, BarCount: 14075)
Calling historicalData(16777217, 140192310324640: Date: 20180112, Open: 64.100000, High: 65.350000, Low: 63.630000, Close: 65.350000, Volume: 774483, Average: 64.858800, BarCount: 24457)
Calling historicalData(16777217, 140192310324448: Date: 20180116, Open: 65.780000, High: 67.000000, Low: 64.610000, Close: 64.950000, Volume: 1031908, Average: 65.927700, BarCount: 32467)
Calling historicalData(16777217, 140192310318496: Date: 20180117, Open: 65.500000, High: 65.810000, Low: 64.040000, Close: 64.940000, Volume: 752364, Average: 64.770750, BarCount: 22903)
Calling historicalData(16777217, 140192310324928: Date: 20180118, Open: 64.800000, High: 65.230000, Low: 64.200000, Close: 64.700000, Volume: 564736, Average: 64.755350, BarCount: 17042)
Calling historicalData(16777217, 140192310325072: Date: 20180119, Open: 64.890000, High: 65.950000, Low: 64.650000, Close: 64.720000, Volume: 658129, Average: 65.014000, BarCount: 18755)
Calling historicalData(16777217, 140192310325216: Date: 20180122, Open: 64.800000, High: 66.870000, Low: 64.730000, Close: 66.740000, Volume: 566553, Average: 65.753050, BarCount: 16272)
Calling historicalData(16777217, 140192310325360: Date: 20180123, Open: 66.950000, High: 68.290000, Low: 66.560000, Close: 68.060000, Volume: 671661, Average: 67.580900, BarCount: 20338)
Calling historicalData(16777217, 140192310325504: Date: 20180124, Open: 68.250000, High: 69.410000, Low: 66.900000, Close: 67.980000, Volume: 959970, Average: 68.117150, BarCount: 29466)
Calling historicalData(16777217, 140192310325648: Date: 20180125, Open: 68.330000, High: 68.920000, Low: 67.880000, Close: 68.900000, Volume: 665466, Average: 68.507900, BarCount: 20322)
Calling historicalData(16777217, 140192310325792: Date: 20180126, Open: 69.100000, High: 70.340000, Low: 69.040000, Close: 70.320000, Volume: 669755, Average: 69.817500, BarCount: 19615)
Calling historicalData(16777217, 140192310325936: Date: 20180129, Open: 70.400000, High: 71.570000, Low: 70.020000, Close: 70.950000, Volume: 762968, Average: 70.828200, BarCount: 23325)
Calling historicalData(16777217, 140192310326080: Date: 20180130, Open: 70.580000, High: 71.960000, Low: 69.600000, Close: 71.900000, Volume: 777056, Average: 71.013050, BarCount: 24213)
Calling historicalData(16777217, 140192310326224: Date: 20180131, Open: 72.400000, High: 73.630000, Low: 72.200000, Close: 73.150000, Volume: 872497, Average: 72.975200, BarCount: 25801)
Calling historicalData(16777217, 140192310326368: Date: 20180201, Open: 73.420000, High: 74.250000, Low: 69.000000, Close: 73.860000, Volume: 1149704, Average: 71.438850, BarCount: 36877)
Calling historicalData(16777217, 140192310326512: Date: 20180202, Open: 73.590000, High: 74.900000, Low: 70.700000, Close: 71.350000, Volume: 1516359, Average: 72.896650, BarCount: 50362)
Calling historicalData(16777217, 140192310326752: Date: 20180205, Open: 71.050000, High: 72.950000, Low: 66.040000, Close: 68.750000, Volume: 1509764, Average: 70.963950, BarCount: 47544)
Calling historicalData(16777217, 140192310327040: Date: 20180206, Open: 68.700000, High: 72.240000, Low: 67.500000, Close: 72.150000, Volume: 1434275, Average: 70.328850, BarCount: 46821)
Calling historicalData(16777217, 140192310326848: Date: 20180207, Open: 71.770000, High: 73.050000, Low: 70.450000, Close: 70.650000, Volume: 927001, Average: 72.113550, BarCount: 29203)
Calling historicalData(16777217, 140192310326656: Date: 20180208, Open: 71.160000, High: 71.820000, Low: 67.090000, Close: 67.600000, Volume: 1063411, Average: 69.301600, BarCount: 34831)
Calling historicalData(16777217, 140192310327232: Date: 20180209, Open: 67.750000, High: 69.170000, Low: 63.300000, Close: 67.110000, Volume: 1817615, Average: 66.171950, BarCount: 61785)
Calling historicalData(16777217, 140192310327376: Date: 20180212, Open: 67.550000, High: 69.690000, Low: 67.200000, Close: 69.350000, Volume: 829939, Average: 68.645400, BarCount: 25870)
Calling historicalData(16777217, 140192310327520: Date: 20180213, Open: 69.240000, High: 70.990000, Low: 68.750000, Close: 70.800000, Volume: 779296, Average: 70.395150, BarCount: 24080)
Calling historicalData(16777217, 140192310327664: Date: 20180214, Open: 71.100000, High: 72.600000, Low: 70.000000, Close: 72.580000, Volume: 772207, Average: 71.706200, BarCount: 24053)
Calling historicalData(16777217, 140192310327808: Date: 20180215, Open: 73.350000, High: 73.450000, Low: 71.840000, Close: 73.140000, Volume: 752165, Average: 72.935800, BarCount: 23814)
Calling historicalData(16777217, 140192310328288: Date: 20180216, Open: 73.500000, High: 73.550000, Low: 72.330000, Close: 72.340000, Volume: 608836, Average: 72.767300, BarCount: 16914)
Calling historicalData(16777217, 140192310328144: Date: 20180220, Open: 72.010000, High: 74.440000, Low: 71.500000, Close: 73.630000, Volume: 890691, Average: 73.426600, BarCount: 25738)
Calling historicalData(16777217, 140192310327904: Date: 20180221, Open: 73.600000, High: 75.170000, Low: 73.450000, Close: 73.850000, Volume: 834251, Average: 74.559450, BarCount: 26049)
Calling historicalData(16777217, 140192310328384: Date: 20180222, Open: 73.860000, High: 75.130000, Low: 73.790000, Close: 74.460000, Volume: 643798, Average: 74.447750, BarCount: 20040)
Calling historicalData(16777217, 140192310328528: Date: 20180223, Open: 74.750000, High: 75.030000, Low: 74.330000, Close: 75.020000, Volume: 596366, Average: 74.745450, BarCount: 17679)
Calling historicalData(16777217, 140192310328672: Date: 20180226, Open: 75.250000, High: 76.250000, Low: 75.250000, Close: 76.240000, Volume: 682149, Average: 75.852900, BarCount: 19996)
Calling historicalData(16777217, 140192310328816: Date: 20180227, Open: 76.450000, High: 76.450000, Low: 75.360000, Close: 75.800000, Volume: 636656, Average: 75.899650, BarCount: 18741)
Calling historicalData(16777217, 140192310328960: Date: 20180228, Open: 76.000000, High: 76.440000, Low: 75.600000, Close: 75.800000, Volume: 574773, Average: 75.969950, BarCount: 15816)
Calling historicalData(16777217, 140192310329104: Date: 20180301, Open: 76.540000, High: 76.540000, Low: 73.250000, Close: 74.780000, Volume: 881505, Average: 74.710100, BarCount: 28275)
Calling historicalData(16777217, 140192310329248: Date: 20180302, Open: 74.310000, High: 75.150000, Low: 72.750000, Close: 75.140000, Volume: 931552, Average: 74.039400, BarCount: 28693)
Calling historicalData(16777217, 140192310317632: Date: 20180305, Open: 75.180000, High: 76.270000, Low: 74.050000, Close: 76.200000, Volume: 712181, Average: 75.457050, BarCount: 21367)
Calling historicalData(16777217, 140192310317488: Date: 20180306, Open: 76.350000, High: 77.110000, Low: 75.600000, Close: 75.650000, Volume: 617349, Average: 76.778100, BarCount: 18280)
Calling historicalData(16777217, 140192310317344: Date: 20180307, Open: 75.990000, High: 77.300000, Low: 75.900000, Close: 77.200000, Volume: 553375, Average: 76.845050, BarCount: 15820)
Calling historicalData(16777217, 140192310317200: Date: 20180308, Open: 77.250000, High: 77.740000, Low: 77.250000, Close: 77.600000, Volume: 484936, Average: 77.542200, BarCount: 14072)
Calling historicalData(16777217, 140192310317056: Date: 20180309, Open: 77.700000, High: 78.950000, Low: 77.630000, Close: 78.930000, Volume: 617069, Average: 78.462000, BarCount: 18324)
Calling historicalData(16777217, 140192310316912: Date: 20180312, Open: 79.500000, High: 80.270000, Low: 79.110000, Close: 80.000000, Volume: 723762, Average: 79.894750, BarCount: 20471)
Calling historicalData(16777217, 140192310316768: Date: 20180313, Open: 80.000000, High: 80.900000, Low: 78.900000, Close: 79.210000, Volume: 867711, Average: 79.798800, BarCount: 27325)
Calling historicalData(16777217, 140192310316624: Date: 20180314, Open: 80.000000, High: 80.320000, Low: 79.540000, Close: 79.740000, Volume: 566616, Average: 79.879600, BarCount: 18074)
Calling historicalData(16777217, 140192310316480: Date: 20180315, Open: 79.900000, High: 80.000000, Low: 78.910000, Close: 79.350000, Volume: 546749, Average: 79.202000, BarCount: 18714)
Calling historicalData(16777217, 140192310316336: Date: 20180316, Open: 79.250000, High: 79.500000, Low: 78.380000, Close: 78.580000, Volume: 726484, Average: 78.789950, BarCount: 18210)
Calling historicalData(16777217, 140192310316192: Date: 20180319, Open: 77.420000, High: 78.750000, Low: 76.270000, Close: 77.000000, Volume: 827655, Average: 77.130500, BarCount: 28198)
Calling historicalData(16777217, 140192310316048: Date: 20180320, Open: 77.460000, High: 79.550000, Low: 77.250000, Close: 79.530000, Volume: 595279, Average: 78.469950, BarCount: 18875)
Calling historicalData(16777217, 140192310315904: Date: 20180321, Open: 79.400000, High: 79.530000, Low: 78.160000, Close: 79.000000, Volume: 650365, Average: 78.998300, BarCount: 19522)
Calling historicalData(16777217, 140192310315760: Date: 20180322, Open: 78.640000, High: 78.700000, Low: 75.910000, Close: 76.350000, Volume: 778647, Average: 77.753700, BarCount: 24433)
Calling historicalData(16777217, 140192310315616: Date: 20180323, Open: 76.430000, High: 77.450000, Low: 74.690000, Close: 74.750000, Volume: 1005688, Average: 75.934250, BarCount: 31117)
Calling historicalData(16777217, 140192310315472: Date: 20180326, Open: 75.550000, High: 78.000000, Low: 74.960000, Close: 78.000000, Volume: 724545, Average: 76.628750, BarCount: 21907)
Calling historicalData(16777217, 140192310315328: Date: 20180327, Open: 78.650000, High: 78.800000, Low: 74.120000, Close: 75.500000, Volume: 871486, Average: 76.945250, BarCount: 26807)
Calling historicalData(16777217, 140192310315184: Date: 20180328, Open: 74.200000, High: 75.500000, Low: 69.310000, Close: 71.350000, Volume: 1734968, Average: 71.314800, BarCount: 57774)
Calling historicalData(16777217, 140192310315040: Date: 20180329, Open: 71.390000, High: 72.770000, Low: 68.260000, Close: 72.300000, Volume: 1691011, Average: 70.868850, BarCount: 52600)
Calling historicalData(16777217, 140192310314896: Date: 20180402, Open: 71.810000, High: 71.810000, Low: 67.750000, Close: 68.250000, Volume: 1295412, Average: 69.065650, BarCount: 41786)
Calling historicalData(16777217, 140192310314752: Date: 20180403, Open: 68.650000, High: 70.700000, Low: 67.770000, Close: 69.250000, Volume: 1347075, Average: 69.182950, BarCount: 44297)
Calling historicalData(16777217, 140192310314608: Date: 20180404, Open: 68.100000, High: 70.940000, Low: 67.310000, Close: 70.900000, Volume: 916870, Average: 69.239700, BarCount: 28747)
Calling historicalData(16777217, 140192310314464: Date: 20180405, Open: 71.550000, High: 72.980000, Low: 70.650000, Close: 71.000000, Volume: 833907, Average: 72.251950, BarCount: 27169)
Calling historicalData(16777217, 140192310314320: Date: 20180406, Open: 71.580000, High: 72.630000, Low: 70.010000, Close: 70.250000, Volume: 768701, Average: 71.229150, BarCount: 24097)
Calling historicalData(16777217, 140192310314176: Date: 20180409, Open: 71.040000, High: 71.920000, Low: 70.050000, Close: 70.250000, Volume: 544898, Average: 71.179050, BarCount: 16984)
Calling historicalData(16777217, 140192310314032: Date: 20180410, Open: 71.250000, High: 71.920000, Low: 70.790000, Close: 71.760000, Volume: 544186, Average: 71.422200, BarCount: 16328)
Calling historicalData(16777217, 140192310313888: Date: 20180411, Open: 71.600000, High: 72.440000, Low: 71.080000, Close: 71.670000, Volume: 463640, Average: 71.835600, BarCount: 13292)
Calling historicalData(16777217, 140192310313744: Date: 20180412, Open: 71.440000, High: 72.610000, Low: 71.440000, Close: 72.280000, Volume: 415622, Average: 72.328750, BarCount: 12676)
Calling historicalData(16777217, 140192310313600: Date: 20180413, Open: 72.010000, High: 72.990000, Low: 71.230000, Close: 71.650000, Volume: 488615, Average: 72.079900, BarCount: 14075)
Calling historicalData(16777217, 140192310313456: Date: 20180416, Open: 71.700000, High: 72.500000, Low: 71.370000, Close: 72.450000, Volume: 355231, Average: 71.941000, BarCount: 11875)
Calling historicalData(16777217, 140192310313312: Date: 20180417, Open: 72.550000, High: 75.460000, Low: 72.550000, Close: 75.400000, Volume: 675998, Average: 74.309250, BarCount: 21354)
Calling historicalData(16777217, 140192310313168: Date: 20180418, Open: 75.550000, High: 77.900000, Low: 75.210000, Close: 77.700000, Volume: 677134, Average: 76.139750, BarCount: 21940)
Calling historicalData(16777217, 140192310313072: Date: 20180419, Open: 77.990000, High: 78.430000, Low: 76.950000, Close: 78.070000, Volume: 814515, Average: 77.721150, BarCount: 26674)
Calling historicalData(16777217, 140192310322000: Date: 20180420, Open: 77.500000, High: 78.290000, Low: 75.800000, Close: 76.630000, Volume: 711019, Average: 76.950400, BarCount: 22029)
Calling historicalData(16777217, 140192310322144: Date: 20180423, Open: 76.600000, High: 77.400000, Low: 75.170000, Close: 76.150000, Volume: 592521, Average: 76.323850, BarCount: 17659)
Calling historicalData(16777217, 140192310322288: Date: 20180424, Open: 76.450000, High: 76.980000, Low: 72.420000, Close: 73.280000, Volume: 1004716, Average: 73.822900, BarCount: 32606)
Calling historicalData(16777217, 140192310322432: Date: 20180425, Open: 73.130000, High: 74.400000, Low: 70.750000, Close: 74.320000, Volume: 877031, Average: 72.399000, BarCount: 28898)
Calling historicalData(16777217, 140192310322576: Date: 20180426, Open: 74.250000, High: 82.050000, Low: 73.920000, Close: 80.900000, Volume: 1023704, Average: 76.403850, BarCount: 33547)
Calling historicalData(16777217, 140192310322720: Date: 20180427, Open: 80.360000, High: 83.240000, Low: 78.300000, Close: 78.400000, Volume: 1617421, Average: 79.796450, BarCount: 53245)
Calling historicalData(16777217, 140192310421360: Date: 20180430, Open: 79.250000, High: 79.800000, Low: 78.050000, Close: 78.580000, Volume: 691444, Average: 78.816600, BarCount: 20803)
Calling historicalDataEnd(16777217, '20180101 08:00:00', '20180501 08:00:00')
Calling contractDetails(16777218, 140192311564688: 208813720,GOOG,STK,,0.0,,,SMART,NASDAQ,USD,GOOG,NMS,False,,combo:,NMS,0.01,ACTIVETIM,AD,ADJUST,ALERT,ALGO,ALLOC,AON,AVGCOST,BASKET,BENCHPX,CASHQTY,COND,CONDORDER,DARKONLY,DARKPOLL,DAY,DEACT,DEACTDIS,DEACTEOD,DIS,DUR,GAT,GTC,GTD,GTT,HID,IBKRATS,ICE,IMB,IOC,LIT,LMT,LOC,MIDPX,MIT,MKT,MOC,MTL,NGCOMB,NODARK,NONALGO,OCA,OPG,OPGREROUT,PEGBENCH,PEGMID,POSTATS,POSTONLY,PREOPGRTH,PRICECHK,REL,REL2MID,RELPCTOFS,RPI,RTH,SCALE,SCALEODD,SCALERST,SIZECHK,SMARTSTG,SNAPMID,SNAPMKT,SNAPREL,STP,STPLMT,SWEEP,TRAIL,TRAILLIT,TRAILLMT,TRAILMIT,WHATIF,SMART,AMEX,NYSE,CBOE,PHLX,ISE,CHX,ARCA,ISLAND,DRCTEDGE,BEX,BATS,EDGEA,CSFBALGO,JEFFALGO,BYX,IEX,EDGX,FOXRIVER,PEARL,NYSENAT,LTSE,MEMX,TPLUS1,PSX,1,0,ALPHABET INC-CL C,,Communications,Internet,Web Portals/ISP,US/Eastern,20220914:0400-20220914:2000;20220915:0400-20220915:2000;20220916:0400-20220916:2000;20220917:CLOSED;20220918:CLOSED;20220919:0400-20220919:2000,20220914:0930-20220914:1600;20220915:0930-20220915:1600;20220916:0930-20220916:1600;20220917:CLOSED;20220918:CLOSED;20220919:0930-20220919:1600,,0,100,,,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,1,[140192311564592: ISIN=US02079K1079;],,COMMON,,,,,,False,False,0,False,,,,,False,)
Calling contractDetailsEnd(16777218)
Calling reqHistoricalDataEx(contract=140192311564640: 208813720,GOOG,STK,,0.0,,,SMART,NASDAQ,USD,GOOG,NMS,False,,combo:, enddate=datetime.datetime(2018, 5, 1, 0, 0), begindate=datetime.datetime(2018, 1, 1, 0, 0), timeframe=5, compression=1, what='TRADES', useRTH=False, tz=None, sessionend=datetime.time(23, 59, 59, 999990))
Calling connectionClosed()
Final Portfolio Value: 100000.00

No backfilling to indicators from rtbars and resample data

Hi atreyu and thanks for this great adaptation for backtrader.

I am playing with your library for one of my projects that involve IB and backtrader, and I am not able to backfill my indicators (simple RSI and MACD) resampling data from rtbars to 1 min data. If no indicator is used, the library works perfectly. Is this supported?

Thanks!

IndexError: list index out of range

Trying to run TestStrategy in paper trading mode. I can get data if ibstore.getbroker() is not run, otherwise the following error appears. Would be grateful for any help!

File "/Users/stefan/strategies/come_on/at_api_test_live.py", line 134, in <module> cerebro.run() File "/Users/stefan/strategies/.venv/lib/python3.9/site-packages/backtrader/cerebro.py", line 1127, in run runstrat = self.runstrategies(iterstrat) File "/Users/stefan/strategies/.venv/lib/python3.9/site-packages/backtrader/cerebro.py", line 1187, in runstrategies self._broker.start() File "/Users/stefan/strategies/.venv/lib/python3.9/site-packages/atreyu_backtrader_api-0.1.0-py3.9.egg/atreyu_backtrader_api/ibbroker.py", line 288, in start File "/Users/stefan/strategies/.venv/lib/python3.9/site-packages/atreyu_backtrader_api-0.1.0-py3.9.egg/atreyu_backtrader_api/ibstore.py", line 2050, in reqAccountUpdates IndexError: list index out of range

clientId needs to be changed every time.

data = IBData(host='127.0.0.1', port=7497, clientId=2, name="GOOG", # Data name dataname='GOOG', # Symbol name secType='STK', # SecurityType is STOCK exchange='SMART',# Trading exchange IB's SMART exchange currency='USD', # Currency of SecurityType fromdate = dt.datetime(2016, 1, 1), todate = dt.datetime(2018, 1, 1), historical=True, what='TRADES', )

The code will hang on there on second run if clientId is not changed

Is it possible to make it work with Delayed market data?

I'm trying to test the example codes but no matter what it keeps returning.
Error: {'reqId': 16777217, 'errorCode': 354, 'errorString': 'Requested market data is not subscribed.Delayed market data is available.Error&BEST/STK/Top&BEST/STK/Top', 'advancedOrderRejectJson': ''}

Error in order cancel - IBKR Paper Trading

Looks like the TWS API for cancelling orders has changed - I get the following error when running in a Paper Trading Environment when I try to cancel orders:

File "/usr/local/lib/python3.10/site-packages/backtrader/strategy.py", line 772, in cancel
self.broker.cancel(order)
File "/usr/local/lib/python3.10/site-packages/atreyu_backtrader_api-0.1.0-py3.10.egg/atreyu_backtrader_api/ibbroker.py", line 324, in cancel
File "/usr/local/lib/python3.10/site-packages/atreyu_backtrader_api-0.1.0-py3.10.egg/atreyu_backtrader_api/ibstore.py", line 1993, in cancelOrder
TypeError: EClient.cancelOrder() missing 1 required positional argument: 'manualCancelOrderTime'

from atreyu_backtrader_api import IBData # does not work for me

Hi, Atreyutrading:

when i run following code on Jupyter Notebook:

from atreyu_backtrader_api import IBData

It shows following error message, can you take a look? thanks a lot

Traceback (most recent call last):

File ~\anaconda3\lib\site-packages\IPython\core\interactiveshell.py:3398 in run_code
exec(code_obj, self.user_global_ns, self.user_ns)

Input In [14] in <cell line: 1>
import backtrader as bt

File ~\anaconda3\lib\site-packages\backtrader_init_.py:62 in
from .cerebro import *

File ~\anaconda3\lib\site-packages\backtrader\cerebro.py:35 in
from .brokers import BackBroker

File ~\anaconda3\lib\site-packages\backtrader\brokers_init_.py:30 in
from .ibbroker import IBBroker

File ~\anaconda3\lib\site-packages\backtrader\brokers\ibbroker.py:30 in
import ib.ext.Order

File ~\anaconda3\lib\site-packages\ib\ext\Order.py:9 in
from ib.lib import Double, Integer

File ~\anaconda3\lib\site-packages\ib\lib_init_.py:239
except (socket.error, ), ex:
^
SyntaxError: invalid syntax

Unable to print logs

Hi, I'm following the example TestPrinter, and I'm unable to print the output.
I just get this object printed as the output:
[<main.TestStrategy at 0x122e96450>]

I'm doing something very basically wrong here?

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.