# Read balances

Source: https://fragment.dev/guides/read-balances

[Documentation index](https://fragment.dev/llms.txt)

<a id="read-balances"></a>

Fragment supports querying a Ledger Account for its latest balances, historical balances and balance changes.

[Visual: readBalances. View on the HTML page.](https://fragment.dev/guides/read-balances)

<a id="latest"></a>

## Latest

Use the `ledgerAccount` query to look up a Ledger Account's balance.

```graphql title="GetBalances query"
query GetBalance(
  $ledgerAccount: LedgerAccountMatchInput!
) {
  ledgerAccount(ledgerAccount: $ledgerAccount) {
    balance
  }
}
```

```json title="GetBalances variables"
{
  "ledgerAccount": {
    "path": "assets/banks/user-cash",
    "ledger": {
      "ik": "quickstart-ledger"
    }
  }
}
```

<a id="aggregated"></a>

## Aggregated

Ledger Accounts have three balances:

- `ownBalance` is the sum of all Ledger Lines posted to the Ledger Account, excluding Ledger Lines in child Ledger Accounts
- `childBalance` is the sum of all Ledger Lines posted to the children of this Ledger Account
- `balance` is the sum of all Ledger Lines posted to this Ledger Account and its children

```graphql title="GetAggregatedBalances query"
query GetAggregatedBalances(
  $ledgerAccount: LedgerAccountMatchInput!
) {
  ledgerAccount(ledgerAccount: $ledgerAccount) {
    childBalance
    balance
  }
}
```

```json title="GetAggregatedBalances variables"
{
  "ledgerAccount": {
    "path": "liabilities/users"
  }
}
```

<a id="consistent"></a>

## Consistent

Balance reads are eventually consistent by default. This means that the balance may not reflect all the Ledger Lines in the account.

To read a strongly consistent balance, a Ledger Account must have its balances updated in a strongly consistent manner. This is set in the Schema on a Ledger Account's `consistencyConfig`:

```json title="Strongly consistent Ledger Accounts" expandable
{
  "key": "strongly-consistent-ledger-accounts",
  "name": "Strongly consistent Ledger Accounts",
  "chartOfAccounts": {
    "defaultCurrency": { "code": "USD" },
    "accounts": [
      {
        "key": "liabilities",
        "type": "liability",
        "children": [
          {
            "key": "users",
            "template": true,
            "consistencyConfig": {
              "totalBalanceUpdates": "strong"
            },
            "children": [
              {
                "key": "available",
                "consistencyConfig": {
                  "totalBalanceUpdates": "strong"
                }
              },
              {
                "key": "pending"
              },
              {
                "key": "blocked"
              }
            ]
          }
        ]
      }
    ]
  }
}
```

Once a Ledger Account's balance is updated consistently, set the `consistencyMode` on balance queries to determine the consistency of the read you issue.

```graphql title="Strongly consistent balance read"
query GetStronglyConsistentBalance(
    $ledgerAccount: LedgerAccountMatchInput!
) {
  ledgerAccount(ledgerAccount: $ledgerAccount) {
    balance(consistencyMode: strong)
  }
}
```

`consistencyMode` can be set to:
- `strong` to perform a strongly consistent balance read
- `eventual` to perform an eventually consistent balance read
- `use_account` to use the Schema value of the Ledger Account's `consistencyConfig.totalBalanceUpdates` setting

```json title="Strongly consistent balance read variables"
{
  "ledgerAccount": {
    "path": "liabilities/users:user-1/available",
    "ledger": {
      "ik": "quickstart-ledger"
    }
  }
}
```

See the [Configure consistency](https://fragment.dev/markdown/guides/configure-consistency.md) section to learn more about consistency modes.

<a id="point-in-time"></a>

## Point in time

To query the balance of a Ledger Account at a particular point in time use the `at` argument:

```graphql title="Balance queries"
query GetHistoricalBalances(
  $ledgerAccount: LedgerAccountMatchInput!
) {
  ledgerAccount(ledgerAccount: $ledgerAccount) {
    end_of_year: balance(at: "1969")
    end_of_month: balance(at: "1969-07")
    end_of_day: balance(at: "1969-07-21")
    end_of_hour: balance(at: "1969-07-21T02")
  }
}
```

If you don't specify `at`, you'll get the [latest balance](https://fragment.dev/markdown/guides/read-balances.md#latest). `at` is supported for all balances and works granularly to the hour.

<a id="net-change"></a>

## Net change

You can also query the net change on a Ledger Account over a specific reporting period. This can be useful for [generating financial statements](https://fragment.dev/markdown/guides/generate-reports.md).

Similar to balances, there are three types of balance changes:

- `ownBalanceChange`, how much `ownBalance` changed
- `childBalanceChange`, how much `childBalance` changed
- `balanceChange`, how much `balance` changed

Balance change queries require you to specify a [`period`](https://fragment.dev/markdown/api-reference/ledger-types.md#scalars-and-enums-period). This can be a year, quarter, month, day or hour.

```graphql title="Balance change queries"
query GetBalanceChanges(
  $ledgerAccount: LedgerAccountMatchInput!
) {
  ledgerAccount(ledgerAccount: $ledgerAccount) {
    ownBalanceChange(period: "1969")
    childBalanceChange(period: "1969")
    balanceChange(period: "1969")
    currentYear: balanceChange(period: "1969")
    lastYear: balanceChange(period: "1968")
    lastYearQ4: balanceChange(period: "1968-Q4")
    lastYearDecember: balanceChange(period: "1968-12")
    lastYearChristmas: balanceChange(period: "1968-12-25")
    lastYearLastHour: balanceChange(period: "1968-12-31T23")
  }
}
```

You can also perform multiple balance queries using aliases.

```json title="Balance change query variables"
{
  "ledgerAccount": {
    "path": "liabilities/users:user-1/available",
    "ledger": {
      "ik": "quickstart-ledger"
    }
  }
}
```

<a id="over-a-period"></a>

## Over a period

Fragment provides two queries for tracking balances and balance changes over time: `balancesDuring` and `balanceChangesDuring`. You can use them to analyze balance history at different granularities.

- `ownBalancesDuring` and `ownBalanceChangesDuring` for a Ledger Account's own balance
- `childBalancesDuring` and `childBalanceChangesDuring` for a Ledger Account's child balance
- `balancesDuring` and `balanceChangesDuring` for a Ledger Account's total balance

To query a Ledger Account's balances, or balance changes, over a period, you must provide:
- `startTime`, a date string in UTC that specifies the first moment of the period
- `duration`, the length of the time period. Duration can be either positive or negative. When negative, the response will be balances, or balance changes, for `duration` period before (not including) `startTime`
- `granularity`, which specifies the unit for `duration`. Valid values are `hourly`, `daily`, or `monthly`

The granularity must have a finer time resolution than the start time string.

| Start Time  | Example Start Time | Valid Granularity | 
| :----- | :---------- | :------------- |
| Year | "2021" | monthly, daily, hourly | 
| Quarter | "2021-Q1" | monthly, daily, hourly | 
| Month | "2021-01" | monthly, daily, hourly | 
| Day | "2021-01-01" | daily, hourly | 
| Hour | "2021-01-01T00" | hourly | 

The maximum absolute value for the duration is granularity dependent. Values outside the ranges defined below will be rejected.

| Granularity | Maximum Duration | Time Period |
| :---------- | :--------------- | :---------- |
| monthly | 240 | 20 years |
| daily | 731 | 2 years including a leap year |
| hourly | 744 | 31 days |

```graphql title="Balance history queries"
query GetBalanceHistory(
  $ledgerAccount: LedgerAccountMatchInput!
) {
  ledgerAccount(ledgerAccount: $ledgerAccount) {
    # Get monthly balances for a year
    yearlyBalances: balancesDuring(
      startTime: "2021"
      duration: 12
      granularity: monthly
    ) {
      startTime
      endTime
      granularity
      nodes {
        at
        amount {
          currency {
            code
          }
          amount
        }
      }
    }

    # Get daily balances for January 2021
    monthlyBalances: balancesDuring(
      startTime: "2021-01"
      duration: 31
      granularity: daily
    ) {
      startTime
      endTime
      granularity
      nodes {
        at
        amount {
          currency {
            code
          }
          amount
        }
      }
    }

    # Get daily balances changes for the two weeks 
    # before the start of Q4 of 2021
    quarterlyChanges: balanceChangesDuring(
      startTime: "2021-Q4"
      duration: -14
      granularity: daily
    ) {
      startTime
      endTime
      granularity
      nodes {
        period
        amount {
          currency {
            code
          }
          amount
        }
      }
    }

    # Get hourly balanceChanges for the 48 hour 
    # period starting on August 9th, 2024 at 
    # 11:00am UTC
    hourlyChanges: balanceChangesDuring(
      startTime: "2024-08-09T11"
      duration: 48
      granularity: hourly
    ) {
      startTime
      endTime
      granularity
      nodes {
        period
        amount {
          currency {
            code
          }
          amount
        }
      }
    }
  }
}
```

The format of the response is:
- `startTime`: The start of the period being queried as an ISO Time string
- `endTime`: The last time in the period being queried as an ISO Time string
- `granularity`: The granularity of the data (monthly, daily, or hourly)
- `nodes`: an array of either [HistoricalBalance](https://fragment.dev/markdown/api-reference/ledger-types.md#scalars-and-enums-historicalbalance) or [BalanceChangeDuring](https://fragment.dev/markdown/api-reference/ledger-types.md#scalars-and-enums-balancechangeduring) objects

For multi-currency Ledger Accounts, you must specify the currency you want to query:

```graphql title="Multi-currency balance history"
query GetMultiCurrencyBalanceHistory(
  $ledgerAccount: LedgerAccountMatchInput!
) {
  ledgerAccount(ledgerAccount: $ledgerAccount) {
    usdBalances: balancesDuring(
      startTime: "2021"
      duration: 12
      granularity: monthly
      currency: { code: USD }
    ) {
      nodes {
        at
        amount {
          amount
        }
      }
    }
    
    gbpChanges: balanceChangesDuring(
      startTime: "2021"
      duration: 100
      granularity: daily
      currency: { code: GBP }
    ) {
      nodes {
        period
        amount {
          amount
        }
      }
    }
  }
}
```

<a id="multi-currency-mode"></a>

## Multi-currency mode

For Ledger Accounts using `currencyMode: multi`, you can either:

1. Use the `currency` argument to query the balance in a specific currency
2. Use plural field names (e.g. `balances`) to query all currency balances

```graphql title="Multi-currency balance queries"
query GetMultiCurrencyBalances(
  $ledgerAccount: LedgerAccountMatchInput!
) {
  ledgerAccount(ledgerAccount: $ledgerAccount) {

    # Query specific currency
    latestUSDBalance: balance(currency: { code: USD })
    latestGBPBalance: balance(currency: { code: GBP })

    # Query all currencies
    balances {
      nodes {
        currency {
          code
        }
        amount
      }
    }

  }
}
```

```json title="Multi-currency balance query variables"
{
  "ledgerAccount": {
    "path": "liabilities/users:user-1/available",
    "ledger": {
      "ik": "quickstart-ledger"
    }
  }
}
```

See [Handle currencies](https://fragment.dev/markdown/guides/handle-currencies.md#read-balances) for a full list of multi-currency balance queries.

<a id="timezone-offsets"></a>

## Timezone offsets

Balance queries respect the Ledger's `balanceUTCOffset` when specifying periods and times. This field is specified when creating the Ledger using the `createLedger` mutation:

```graphql title="createLedger mutation" expandable
mutation CreateLedger(
  $ik: SafeString!
  $ledger: CreateLedgerInput!
  $schema: SchemaMatchInput
) {
  createLedger(
    ik: $ik,
    ledger: $ledger,
    schema: $schema
  ) {
    ... on CreateLedgerResult {
      ledger {
        ik
        name
        created
        balanceUTCOffset
        schema {
          key
        }
      }
    }
    ... on Error {
      code
      message
    }
  }
}
```

```json title="createLedger variables with timezone offset"
{
  "ik": "quickstart-ledger",
  "ledger": {
    "name": "Quickstart Ledger",
    "balanceUTCOffset": "-08:00"
  },
  "schema": {
    "key": "quickstart-schema"
  }
}
```

The `balanceUTCOffset` is specified as a `UTCOffset` string in the format "±HH:00". All hour-aligned offsets from -11:00 to +12:00 are supported. For example:
- `"-08:00"` for Pacific Time (UTC-8)
- `"-05:00"` for Eastern Time (UTC-5)
- `"+00:00"` for UTC
- `"+01:00"` for Central European Time (UTC+1)

If not specified, the Ledger will use UTC (offset of "+00:00") for balance calculations.

When querying balances, the offset affects how periods and times are interpreted:

- If a Ledger has an offset of `-08:00`, then querying `balance(at: "1969-01-31")` returns the balance at midnight PT on that date, or 8am on 1969-02-01 UTC.
- Querying `balanceChange(period: "1969")` returns the net change between 8am on 1969-01-01 UTC and 8am on 1970-01-01 UTC. This gives you the net change between midnights local time.
- Daylight savings is ignored, so every day throughout the year has exactly 24 hours.
