tradingenv.broker package¶
Submodules¶
tradingenv.broker.allocation module¶
Provides an extented python dictionary with handy methods when the dict is mapping contracts to quantities (either nr of contracts of portfolio weight).
- class tradingenv.broker.allocation.NrContracts(mapping: Dict[AbstractContract, float] = None, keys: Sequence[AbstractContract] = None, values: Sequence[float] = None)[source]¶
Bases:
_Allocation
A dictionary mapping contracts to number of contracts.
To initialize allocation you need to pass either 'mapping' OR 'keys' and 'values'.
- Parameters:
mapping -- A dictionary mapping instances of AbstractContract to a float representing the target allocation expressed in a whatever unit of measurement (e.g. weight or number of contracts).
keys -- A sequence of AbstractContract instances, representing the keys of the dictionary to be constructed.
values -- A sequence of floats, representing the values of the dictionary to be constructed.
- class tradingenv.broker.allocation.Weights(mapping: Dict[AbstractContract, float] = None, keys: Sequence[AbstractContract] = None, values: Sequence[float] = None)[source]¶
Bases:
_Allocation
A dictionary mapping contracts to portfolio weight.
To initialize allocation you need to pass either 'mapping' OR 'keys' and 'values'.
- Parameters:
mapping -- A dictionary mapping instances of AbstractContract to a float representing the target allocation expressed in a whatever unit of measurement (e.g. weight or number of contracts).
keys -- A sequence of AbstractContract instances, representing the keys of the dictionary to be constructed.
values -- A sequence of floats, representing the values of the dictionary to be constructed.
tradingenv.broker.broker module¶
This module provides the core logic to perform portfolio _rebalancing. Holdings (cash and contracts) are held in a Brokerage account and historical _rebalancing are keep in TrackRecord.
- class tradingenv.broker.broker.Broker(exchange: ~tradingenv.exchange.Exchange, base_currency: ~tradingenv.contracts.Cash = Cash(USD), deposit: float = 100.0, fees: ~tradingenv.broker.fees.IBrokerFees = <tradingenv.broker.fees.BrokerFees object>, epsilon: float = 1e-07)[source]¶
Bases:
object
This class allows to simulate a sequence of _rebalancing requests.
- _holdings_margins¶
A dictionary mapping contracts to margins deposited at the clearing house, e.g. when buying derivatives products such as futures.
- Type:
Dict[AbstractContract, float]
- _holdings_quantity¶
A dictionary mapping contracts to number of contracts held now.
- Type:
Dict[AbstractContract, float]
- track_record¶
Keeps track of historical _rebalancing request.
- Type:
- Parameters:
- accrued_interest(now: datetime, accrue: bool = False) float [source]¶
- Parameters:
now (datetime) -- Current time, used to calculate how long it has passed since the last time that interest rates were deposited or charged.
accrue (bool) -- If True, the interest rate will be accrued, i.e. charged if negative or deposited if positive. The interest rate applied is determined by Broker.fees.interest_rate.
Notes
No interest rate paid on margins. This is a realistic conservative assumption (e.g. Interactive Brokers does not pay interest rates on margins and financial instrument cannot be deposited as _margin).
- Returns:
Amount of interest rate owed (either positive or negative) since
when if was last deposited/charged from the account's holdings.
- property holdings_margins: Dict[AbstractContract, float]¶
- property holdings_quantity: Dict[AbstractContract, float]¶
- holdings_values(kind: str = 'notional') Dict[AbstractContract, float] [source]¶
Returns np.array with state of all positions within the portfolio (cash included) in base currency. The array has as many entries as traded contracts. Notional values, so transaction_price * multiplier.
- holdings_weights() Dict[AbstractContract, float] [source]¶
Relative weights of the notional traded value over NLV. Returns current weights of the portfolio as positions values (including market spread) divided by the net liquidation state of the account (including market spread).
- marking_to_market(contract: AbstractContract | Sequence[AbstractContract] = None)[source]¶
- Parameters:
contract (Union[AbstractContract, Sequence[AbstractContract]]) -- An optional contract or sequence of contracts to for which marking-to-market has to be performed. If blank, all contracts will be assumed to be updated.
References
https://www.cmegroup.com/education/courses/introduction-to-futures/mark-to-market.html https://www.cmegroup.com/education/courses/introduction-to-futures/margin-know-what-is-needed.html
- net_liquidation_value(raise_if_broke: bool = True) float [source]¶
- Parameters:
raise_if_broke (bool) -- An EndOfEpisodeError will be raised if the notional liquidation value of the account is non-positive.
- Returns:
The net liquidation value of the account pricing long (short) position
using bid (ask) prices.
- rebalance(rebalancing: Rebalancing)[source]¶
Given a _rebalancing object, execute all trades needed to perform the _rebalancing.
Developer notes¶
The _rebalancing logic is slit between Rebalancing and Broker. Rebalancing is responsible for calculating (but not executing) the trading instructions (i.e. a list of trades), wheres Broker is responsible for anything else (i.e. pre-processing, execution and post-processing). This design allows to optionally compute the trades for a variety of _rebalancing objects and see what the trades would be, without performing any _rebalancing. Also, the separation of concerns between calculating the trades and execution the trades makes it easier to test the code.
- transact(trade: Trade)[source]¶
- Parameters:
trade (Trade) -- A trade instance to be executed.
Notes
Transacting in long lasting positions might lead to numerical errors in the order of ~1e-15. It's a design choice not to deal with such errors because for prices --> +inf, _holdings_quantity --> 0 < 1e-15. In other words, we don't deal with such numerical errors to avoid unexpected side effects when asset prices are relatively too high. https://floating-point-gui.de/basic/
tradingenv.broker.fees module¶
- class tradingenv.broker.fees.BrokerFees(markup: float = 0.0, interest_rate: ~tradingenv.contracts.Rate = Rate(FED funds rate), proportional: float = 0.0, fixed: float = 0.0)[source]¶
Bases:
IBrokerFees
No broker fees of any sort will be applied when using this class.
- Parameters:
markup (float) -- A non-negative CAGR, zero by default. This mark-up is the profit of the broker when applying the interest rate to idle cash and loans. For example, if interest_rate is 0.03 (3%) and fees=0.01 (1%), CAGR on idle cash will be 2% and cost of loans will be 4%.
interest_rate (Rate) -- This interest rate is used to: (1) generate a positive stream of cash flows on idle cash (e.g. when the portfolio is not fully invested) and (2) generate a negative stream of cash flows on loans (e.g. borrowed cash to pay in a leveraged portfolio of ETFs). By default, this is Rate('FED funds rate') and it's expressed in terms of compounded annual growth rate (CAGR).
proportional (float) -- Broker fees to be applied to the notional traded value of the security. E.g. if 0.01 (1%) mean that 1 USD is paid for every 100 USD traded.
fixed (float) -- Fixed broker fees to be applied to each trade, regardless the notional traded value of trade.
- class tradingenv.broker.fees.IBrokerFees(markup: float = 0.0, interest_rate: ~tradingenv.contracts.Rate = Rate(FED funds rate), proportional: float = 0.0, fixed: float = 0.0)[source]¶
Bases:
ABC
- Parameters:
markup (float) -- A non-negative CAGR, zero by default. This mark-up is the profit of the broker when applying the interest rate to idle cash and loans. For example, if interest_rate is 0.03 (3%) and fees=0.01 (1%), CAGR on idle cash will be 2% and cost of loans will be 4%.
interest_rate (Rate) -- This interest rate is used to: (1) generate a positive stream of cash flows on idle cash (e.g. when the portfolio is not fully invested) and (2) generate a negative stream of cash flows on loans (e.g. borrowed cash to pay in a leveraged portfolio of ETFs). By default, this is Rate('FED funds rate') and it's expressed in terms of compounded annual growth rate (CAGR).
proportional (float) -- Broker fees to be applied to the notional traded value of the security. E.g. if 0.01 (1%) mean that 1 USD is paid for every 100 USD traded.
fixed (float) -- Fixed broker fees to be applied to each trade, regardless the notional traded value of trade.
- class tradingenv.broker.fees.InteractiveBrokersFees(markup: float = 0.0, interest_rate: ~tradingenv.contracts.Rate = Rate(FED funds rate), proportional: float = 0.0, fixed: float = 0.0)[source]¶
Bases:
IBrokerFees
Replicate Interactive Broker commisions.
References
https://www.interactivebrokers.com/en/index.php?f=1590
- Parameters:
markup (float) -- A non-negative CAGR, zero by default. This mark-up is the profit of the broker when applying the interest rate to idle cash and loans. For example, if interest_rate is 0.03 (3%) and fees=0.01 (1%), CAGR on idle cash will be 2% and cost of loans will be 4%.
interest_rate (Rate) -- This interest rate is used to: (1) generate a positive stream of cash flows on idle cash (e.g. when the portfolio is not fully invested) and (2) generate a negative stream of cash flows on loans (e.g. borrowed cash to pay in a leveraged portfolio of ETFs). By default, this is Rate('FED funds rate') and it's expressed in terms of compounded annual growth rate (CAGR).
proportional (float) -- Broker fees to be applied to the notional traded value of the security. E.g. if 0.01 (1%) mean that 1 USD is paid for every 100 USD traded.
fixed (float) -- Fixed broker fees to be applied to each trade, regardless the notional traded value of trade.
tradingenv.broker.rebalancing module¶
- class tradingenv.broker.rebalancing.Rebalancing(contracts: Sequence[AbstractContract] = None, allocation: Sequence[float] = None, measure: str = 'weight', absolute: bool = True, fractional: bool = True, margin: float = 0.0, time: datetime = None)[source]¶
Bases:
object
Private class returned by PortfolioSpace._make_rebalancing_request and passed to RebalancingResponse during its initialization.
- Parameters:
contracts -- A sequence of contracts. The i-th contract is associated with the i-th element in 'allocation'.
allocation -- A sequence of target portfolio allocations of the _rebalancing. The i-th allocation is associated with the i-th element in 'contracts'. The representation of the values in the sequence depends on the parameter 'kind'.
measure -- The unit of measurement of the parameter 'allocation'. If: - 'weight': a 0.2 would mean 20% of the net liquidation value of the current portfolio. - 'nr-contracts': a 21 would mean 21 contracts.
absolute -- If True (default), 'allocation' is assumed to represents the desired target allocation. For example, if allocation={ETF(SPY): 0.03} and measure='weight', then the desired _rebalancing will result in an allocation in ETF(SPY) corresponding to 3% of the net liquidation value and the remaining 97% in cash. If False, 'allocation' is assumed to represent the desired change from the current allocation. or example, if allocation={ETF(SPY): 0.03} and measure='weight', then the desired _rebalancing will result in the previously held portfolio with 3% less of cash and 3% more of ETF(SPY).
fractional -- True by default. If false, decimals will be ignored from every element of 'allocation'.
margin -- A non-negative float. Rebalancing of positions which are not at least different by '_margin' in absolute value, will not be executed. Setting a small positive value (e.g. 0.02==2%) might be a good practice to reduce transaction costs. Skip trade if the absolute weight imbalance is below the margin AND the target weight is different from zero. The latter condition allows to liquidate a position in the situation where we hold in the portfolio a contract with a tiny weight below the margin.
time -- Time of the _rebalancing request. Current time by default.
Notes
Target weights are applied to the net liquidation value of the account before paying transaction costs to make the problem more trackable). Therefore, in presence transaction costs, the amount of cash in the broker account will be -x where x are the broker commissions paid.
tradingenv.broker.track_record module¶
TrackRecord stores historical _rebalancing execution performed by Broker.
- class tradingenv.broker.track_record.TrackRecord[source]¶
Bases:
object
Stores historical _rebalancing requests and _rebalancing.
- fig_capital_asset_pricing_model() <Mock name='mock.graph_objs.Figure' id='136273437610528'> [source]¶
- fig_historical_portfolio_weights_actual(group_futures: bool = True, post_rebalancing: bool = True) <Mock name='mock.graph_objs.Figure' id='136273437610528'> [source]¶
- fig_historical_portfolio_weights_diff(group_futures: bool = True, post_rebalancing: bool = True) <Mock name='mock.graph_objs.Figure' id='136273437610528'> [source]¶
- classmethod load(path: str) TrackRecord [source]¶
- net_liquidation_value(before_rebalancing=True, burn: bool = False, name: str = 'Net liquidation value', index_name: str = 'Date') <Mock name='mock.DataFrame' id='136273440799872'> [source]¶
- Parameters:
before_rebalancing
burn (bool) -- Default is False (least surprise principle). If True, initial checkpoints with no trades (i.e. when the portfolio is cash only) will be discarded when calling TrackRecord.to_frame, unless a burn argument is explicitly passed to TrackRecord.to_frame.
name
index_name
- transaction_costs(burn: bool = False, index_name: str = 'Date', cumulative: bool = True) <Mock name='mock.DataFrame' id='136273440799872'> [source]¶
- class tradingenv.broker.track_record.TrackRecordComparison(track_records: Sequence[TrackRecord])[source]¶
Bases:
object
tradingenv.broker.trade module¶
Execution details of a single trade.
- class tradingenv.broker.trade.Trade(time: ~datetime.datetime, contract: ~tradingenv.contracts.AbstractContract, quantity: float, bid_price: float, ask_price: float, broker_fees: ~tradingenv.broker.fees.IBrokerFees = <tradingenv.broker.fees.BrokerFees object>)[source]¶
Bases:
object
Execution details of a single trade. This class is instanced by RebalancingResponse.
- acq_price¶
Average acquisition or liquidation price across all lots to execute the trade. By default, there is no market impact nor slippage. Therefore, avg_price corresponds to the bid price (ask price) in case of buy (sell).
- Type:
float
- cost_of_cash¶
Cash to be paid (earned) upfront to buy (sell) the contract.
- Type:
float
- cost_of_commissions¶
Broker commissions paid when transacting.
- Type:
float
- Parameters:
time (datetime) -- Execution time of the trade.
contract (AbstractContract) -- Traded contract.
quantity (float) -- Traded quantity. A negative number denotes a sell, liquidation or short-selling.
bid_price (float) -- Bid price in the limit order book of the contract. Bid price must be non-greater then the ask price.
ask_price (float) -- Ask price in the limit order book of the contract. Ask price must be non.smaller than the bid price.
broker_fees (IBrokerFees) -- An concrete implementation of AbstractBrokerFees, responsible to calculate the total broker fees to be paid for the trade.
- acq_price¶
- ask_price¶
- bid_price¶
- contract¶
- cost_of_cash¶
- cost_of_commissions¶
- cost_of_spread¶
- notional¶
- quantity¶
- time¶