book
Checkout our new book! Hands on AI Trading with Python, QuantConnect, and AWS Learn More arrow

Portfolio

Cashbook

Introduction

The CashBook is a dictionary where the keys are currency tickers and the values are Cash objects. The Cash objects track the amount of each currency in the portfolio. As you buy and sell securities, LEAN credits and debits the Cash objects to reflect your cash holdings.

Account Currency

The default account currency is USD, but you can change it. All of the properties of the Portfolio object that return a currency value denominate the currency value in your account currency. Depending on your account currency and security subscriptions, LEAN may add internal security subscriptions to calculate the ValueInAccountCurrencyvalue_in_account_currency. For example, if you only add BTCETH to your algorithm and set the account currency to USDT, LEAN adds BTCUSDT and ETHUSDT as internal feeds.

To get your account currency, use the AccountCurrencyaccount_currency property.

var accountCurrency = AccountCurrency;
account_currency = self.account_currency

To set your account currency, in the Initializeinitialize method, call the SetAccountCurrencyset_account_currency method. You can only set the account currency once. LEAN ignores each additional call to SetAccountCurrencyset_account_currency.

SetAccountCurrency("EUR");
self.set_account_currency("EUR")

Settled vs Unsettled Cash

The Portfolioportfolio has two independent cashbooks. The CashBookcash_book tracks settled cash and the UnsettledCashBookunsettled_cash_book tracks unsettled cash, which you can't spend. If you trade with a margin account, trades settle immediately so LEAN credits and debits the CashBookcash_book at the time of the trade. In some cases, transactions can take time to settle. For example, Equity trades in a cash account settle in T+3. Therefore, if you sell shares of stock on Monday, the transaction settles on Thursday. In contrast, Option trades settle in T+1.

var settledCashBook = Portfolio.CashBook;
var unsettledCashBook = Portfolio.UnsettledCashBook;
settled_cash_book = self.portfolio.cash_book
unsettled_cash_book = self.portfolio.unsettled_cash_book

Track Cash Balances

To get the balance of a currency in the cash book, use the Amountamount property.

var usd = Portfolio.CashBook["USD"].Amount;
var btc = Portfolio.CashBook["BTC"].Amount;
# Return the cash book balance in US Dollar amount.
usd = self.portfolio.cash_book["USD"].amount
# Return the cash book balance in Bitcoin amount.
btc = self.portfolio.cash_book["BTC"].amount

To get the value of a currency in the cash book, denominated in your account currency, use the ValueInAccountCurrencyvalue_in_account_currency property.

// Return the cash book value of Ethereum in account currency (US Dollar, Euro, etc.) amount.
var ethValue = Portfolio.CashBook["ETH"].ValueInAccountCurrency;
# Return the cash book value of Ethereum in account currency (US Dollar, Euro, etc.) amount. 
eth_value = self.portfolio.cash_book["ETH"].value_in_account_currency

Deposits and Withdrawals

In backtests, you can add and remove cash from the cash book. To add or remove cash, call the AddAmountadd_amount method.

// Adjust the backtesting cashbook balances to add 100 USD and subtract 1.5 BTC.
var newUSDBalance = Portfolio.CashBook["USD"].AddAmount(100);
var newBTCBalance = Portfolio.CashBook["BTC"].AddAmount(-1.5m);
# Adjust the backtesting cashbook balances to add 100 USD and subtract 1.5 BTC.
new_usd_balance = self.portfolio.cash_book["USD"].add_amount(100)
new_btc_balance = self.portfolio.cash_book["BTC"].add_amount(-1.5)

In live trading, add and withdraw cash through your brokerage account. If you adjust the cash balances in your algorithm with the AddAmountadd_amount method, the cash balance in your algorithm will be out of sync with the cash balance in your brokerage account.

Currency Symbols

A currency symbol is a graphic that represents the currency name. For example, $ is for dollars, € for euros, and ฿ for Bitcoin. To get the symbol of a currency in the cash book, use CurrencySymbolcurrency_symbol property.

var usdSymbol = Portfolio.CashBook["USD"].CurrencySymbol;
usd_symbol = self.portfolio.cash_book["USD"].currency_symbol

Conversion Rates

To get the conversion rate for a currency in the cashbook to your account currency, use the ConversionRateconversion_rate property.

var eurConversionRate = Portfolio.CashBook["EUR"].ConversionRate;
eur_conversion_rate = self.portfolio.cash_book["EUR"].conversion_rate

Examples

The following examples demonstrate common practices for controlling the portfolio cashbook.

Example 1: Dollar Cost Averaging

The following algorithm deposits USD 1000 on every month's start and buys SPY with the deposited cash. It results in a dollar cost averaging investment strategy on the overall market.

public class PortfolioCashbookAlgorithm : QCAlgorithm
{
    private Symbol _spy;
    private decimal _deposit = 1000m;

    public override void Initialize()
    {
        SetStartDate(2021, 1, 1);
        SetEndDate(2022, 1, 1);
        SetCash(1);

        // Request SPY data to trade the overall market representative.
        _spy = AddEquity("SPY").Symbol;

        // Deposit each month start and invest in SPY by dollar cost averaging.
        Schedule.On(
            DateRules.MonthStart(_spy),
            TimeRules.AfterMarketOpen(_spy, 0),
            DepositAndRebalance
        );

        // To warm up the price data of SPY to calculate the quantity to be brought.
        SetWarmUp(1);
    }

    private void DepositAndRebalance()
    {
        // Deposit the account currency's preset level ($1000) at the start of the month.
        // Simulate the monthly salary deposit for dollar cost-averaging investment in the market.
        Portfolio.CashBook[AccountCurrency].AddAmount(_deposit);

        // Calculate the number of shares that can be invested using the deposited amount.
        var quantity = Math.Floor(_deposit / Securities[_spy].Price);
        MarketOrder(_spy, quantity);
    }
}
class PortfolioCashbookAlgorithm(QCAlgorithm):
    deposit = 1000

    def initialize(self) -> None:
        self.set_start_date(2021, 1, 1)
        self.set_end_date(2022, 1, 1)
        self.set_cash(1)

        # Request SPY data to trade the overall market representative.
        self.spy = self.add_equity("SPY").symbol

        # Deposit each month start and invest in SPY by dollar cost averaging.
        self.schedule.on(
            self.date_rules.month_start(self.spy),
            self.time_rules.after_market_open(self.spy, 0),
            self.deposit_and_rebalance
        )
        
        # To warm up the price data of SPY to calculate the quantity to be brought.
        self.set_warm_up(1)
    
    def deposit_and_rebalance(self) -> None:
        # Deposit the account currency's preset level ($1000) at the month's start.
        # Simulate the monthly salary deposit for dollar cost-averaging investment in the market.
        self.portfolio.cash_book[self.account_currency].add_amount(self.deposit)

        # Calculate the number of shares that can be invested using the deposited amount.
        quantity = self.deposit // self.securities[self.spy].price
        self.market_order(self.spy, quantity)

Example 2: Crypto Cashbook

This example trades an EMA cross strategy on the ETH-BTC crypto pair in a cash account. To obtain the maximum tradable order size, we need to use the cash book and check the amount of BTC in long ETHBTC trades and in short ETHBTC trades to avoid insufficient initial margin.

public class PortfolioCashbookAlgorithm : QCAlgorithm
{
    private Symbol _ethbtc;
    private ExponentialMovingAverage _ema;
    // Set a buffer to avoid insufficient margin due to the price fluctuation.
    private decimal _buffer = 0.01m;

    public override void Initialize()
    {
        SetStartDate(2021, 8, 1);
        SetEndDate(2021, 9, 1);
        // Set the account currency as USDT and the starting cash in a cash account.
        SetBrokerageModel(BrokerageName.Coinbase, AccountType.Cash);
        SetAccountCurrency("USDT", 100);
        SetCash("BTC", 100);
        SetCash("ETH", 2000);

        // We would like to trade the EMA cross between 2 popular cryptos, BTC & ETH,
        // so request ETHBTC data to find trading opportunities.
        _ethbtc = AddCrypto("ETHBTC", Resolution.Minute, market: Market.Coinbase).Symbol;

        // Add automatic-updating EMA indicator for trend trade signal emission.
        _ema = EMA(_ethbtc, 50, Resolution.Daily);
        // Warm up the indicator for its readiness usage immediately.
        WarmUpIndicator(_ethbtc, _ema, Resolution.Daily);
    }

    public override void OnData(Slice slice)
    {
        if (slice.Bars.TryGetValue(_ethbtc, out var bar) && _ema.IsReady)
        {
            // ETHBTC's current price is higher than EMA, suggesting an uptrend.
            if (bar.Close > _ema && !Portfolio[_ethbtc].IsLong)
            {
                // Convert to the corresponding quantity of the quote currency.
                MarketOrder(_ethbtc, Portfolio.CashBook["BTC"].Amount * (1m - _buffer) / bar.Close);
            }
            // ETHBTC's current price is below the EMA, suggesting a downtrend.
            else if (bar.Close < _ema && !Portfolio[_ethbtc].IsShort)
            {
                MarketOrder(_ethbtc, -Portfolio.CashBook["ETH"].Amount * (1m - _buffer));
            }
        }
    }
}
class PortfolioCashbookAlgorithm(QCAlgorithm):

    buffer = 0.01

    def initialize(self) -> None:
        self.set_start_date(2021, 8, 1)
        self.set_end_date(2021, 9, 1)
        # Set the account currency as USDT and set the starting cash in a cash account.
        self.set_brokerage_model(BrokerageName.COINBASE, AccountType.CASH)
        self.set_account_currency("USDT", 100)
        self.set_cash("BTC", 100)
        self.set_cash("ETH", 2000)

        # We would like to trade the EMA cross between 2 popular cryptos BTC & ETH,
        # so we are requesting ETHBTC data to find trading opportunities.
        self.ethbtc = self.add_crypto("ETHBTC", Resolution.MINUTE, Market.COINBASE).symbol

        # Add automatic-updating EMA indicator for trend trade signal emission.
        self._ema = self.ema(self.ethbtc, 50, Resolution.DAILY)
        # Warm up the indicator for its readiness usage immediately.
        self.warm_up_indicator(self.ethbtc, self._ema, Resolution.DAILY)

    def on_data(self, slice: Slice) -> None:
        bar = slice.bars.get(self.ethbtc)
        if bar and self._ema.is_ready:
            ema = self._ema.current.value
            # ETHBTC's current price is higher than EMA, suggesting an uptrend.
            if bar.close > ema and not self.portfolio[self.ethbtc].is_long:
                # Convert to the corresponding quantity of the quote currency.
                self.market_order(self.ethbtc, self.portfolio.cash_book["BTC"].amount * (1 - self.buffer) / bar.close)
            # ETHBTC's current price is below the EMA, suggesting a downtrend.
            elif bar.close < ema and not self.portfolio[self.ethbtc].is_short:
                self.market_order(self.ethbtc, -self.portfolio.cash_book["ETH"].amount)

You can also see our Videos. You can also get in touch with us via Discord.

Did you find this page helpful?

Contribute to the documentation: