Skip to content

Commit a0ff197

Browse files
committed
new: function to retrieve all owned securities' price & value
Ref: gboudreau/ws-api-python#26
1 parent c1051bf commit a0ff197

2 files changed

Lines changed: 37 additions & 0 deletions

File tree

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@ foreach ($historical_fins as $hf) {
9191
echo " - $hf->date = \$" . number_format($hf->netLiquidationValueV2->amount) . " - " . number_format($hf->netDepositsV2->amount) . " (deposits) = " . number_format($hf->netLiquidationValueV2->amount - $hf->netDepositsV2->amount) . " (gains)\n";
9292
}
9393

94+
echo "All owned securities value and price:\n";
95+
$positions = $ws->getIdentityPositions();
96+
foreach ($positions as $pos) {
97+
$sec = $ws->getSecurityMarketData($pos->security->id);
98+
$account_id = $pos->accounts[0]->id;
99+
echo "- [$account_id]\t{$sec->stock->symbol}\t\tbookValue:{$pos->bookValue->amount}\taveragePrice:{$pos->averagePrice->amount}\tmarketAveragePrice:{$pos->marketAveragePrice->amount}\tmarketBookValue:{$pos->marketBookValue->amount}\ttotalValue:{$pos->totalValue->amount}\tunrealizedReturns:{$pos->unrealizedReturns->amount}\tmarketUnrealizedReturns:{$pos->marketUnrealizedReturns->amount}\n";
100+
}
101+
94102
foreach ($accounts as $account) {
95103
echo "Account: $account->description ($account->number)\n";
96104
if ($account->description === $account->unifiedAccountType) {

src/WealthsimpleAPI.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ protected static function getGraphQLQuery(string $query_name): string {
2929
case 'FetchIdentityHistoricalFinancials': return "query FetchIdentityHistoricalFinancials(\$identityId: ID!, \$currency: Currency!, \$startDate: Date, \$endDate: Date, \$first: Int, \$cursor: String, \$accountIds: [ID!]) {\n identity(id: \$identityId) {\n id\n financials(filter: {accounts: \$accountIds}) {\n historicalDaily(\n currency: \$currency\n startDate: \$startDate\n endDate: \$endDate\n first: \$first\n after: \$cursor\n ) {\n edges {\n node {\n ...IdentityHistoricalFinancials\n __typename\n }\n __typename\n }\n pageInfo {\n hasNextPage\n endCursor\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n }\n\n fragment IdentityHistoricalFinancials on IdentityHistoricalDailyFinancials {\n date\n netLiquidationValueV2 {\n amount\n currency\n __typename\n }\n netDepositsV2 {\n amount\n currency\n __typename\n }\n __typename\n }";
3030
case 'FetchCorporateActionChildActivities': return "query FetchCorporateActionChildActivities(\$activityCanonicalId: String!) {\n corporateActionChildActivities(\n condition: {activityCanonicalId: \$activityCanonicalId}\n ) {\n nodes {\n ...CorporateActionChildActivity\n __typename\n }\n __typename\n }\n}\n\nfragment CorporateActionChildActivity on CorporateActionChildActivity {\n canonicalId\n activityCanonicalId\n assetName\n assetSymbol\n assetType\n entitlementType\n quantity\n currency\n price\n recordDate\n __typename\n}";
3131
case 'FetchBrokerageMonthlyStatementTransactions': return "query FetchBrokerageMonthlyStatementTransactions(\$period: String!, \$accountId: String!) {\n brokerageMonthlyStatements(period: \$period, accountId: \$accountId) {\n id\n statementType\n createdAt\n data {\n ... on BrokerageMonthlyStatementObject {\n ...BrokerageMonthlyStatementObject\n __typename\n }\n __typename\n }\n __typename\n }\n}\n\nfragment BrokerageMonthlyStatementObject on BrokerageMonthlyStatementObject {\n custodianAccountId\n activitiesPerCurrency {\n currency\n currentTransactions {\n ...BrokerageMonthlyStatementTransactions\n __typename\n }\n __typename\n }\n currentTransactions {\n ...BrokerageMonthlyStatementTransactions\n __typename\n }\n isMultiCurrency\n __typename\n}\n\nfragment BrokerageMonthlyStatementTransactions on BrokerageMonthlyStatementTransactions {\n balance\n cashMovement\n unit\n description\n transactionDate\n transactionType\n __typename\n}";
32+
case 'FetchIdentityPositions': return "query FetchIdentityPositions(\$identityId: ID!, \$currency: Currency!, \$first: Int, \$cursor: String, \$accountIds: [ID!], \$aggregated: Boolean, \$currencyOverride: CurrencyOverride, \$sort: PositionSort, \$sortDirection: PositionSortDirection, \$filter: PositionFilter, \$since: PointInTime, \$includeSecurity: Boolean = false, \$includeAccountData: Boolean = false, \$includeOneDayReturnsBaseline: Boolean = false) {\n identity(id: \$identityId) {\n id\n financials(filter: {accounts: \$accountIds}) {\n current(currency: \$currency) {\n id\n positions(\n first: \$first\n after: \$cursor\n aggregated: \$aggregated\n filter: \$filter\n sort: \$sort\n sortDirection: \$sortDirection\n ) {\n edges {\n node {\n ...PositionV2\n __typename\n }\n __typename\n }\n pageInfo {\n hasNextPage\n endCursor\n __typename\n }\n totalCount\n status\n hasOptionsPosition\n hasCryptoPositionsOnly\n securityTypes\n securityCurrencies\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}\n\nfragment SecuritySummary on Security {\n ...SecuritySummaryDetails\n stock {\n ...StockSummary\n __typename\n }\n quoteV2(currency: null) {\n ...SecurityQuoteV2\n __typename\n }\n optionDetails {\n ...OptionSummary\n __typename\n }\n __typename\n}\n\nfragment SecuritySummaryDetails on Security {\n id\n currency\n inactiveDate\n status\n wsTradeEligible\n equityTradingSessionType\n securityType\n active\n securityGroups {\n id\n name\n __typename\n }\n features\n logoUrl\n __typename\n}\n\nfragment StockSummary on Stock {\n name\n symbol\n primaryMic\n primaryExchange\n __typename\n}\n\nfragment StreamedSecurityQuoteV2 on UnifiedQuote {\n __typename\n securityId\n ask\n bid\n currency\n price\n sessionPrice\n quotedAsOf\n ... on EquityQuote {\n marketStatus\n askSize\n bidSize\n close\n high\n last\n lastSize\n low\n open\n mid\n volume: vol\n referenceClose\n __typename\n }\n ... on OptionQuote {\n marketStatus\n askSize\n bidSize\n close\n high\n last\n lastSize\n low\n open\n mid\n volume: vol\n breakEven\n inTheMoney\n liquidityStatus\n openInterest\n underlyingSpot\n __typename\n }\n}\n\nfragment SecurityQuoteV2 on UnifiedQuote {\n ...StreamedSecurityQuoteV2\n previousBaseline\n __typename\n}\n\nfragment OptionSummary on Option {\n underlyingSecurity {\n ...UnderlyingSecuritySummary\n __typename\n }\n maturity\n osiSymbol\n expiryDate\n multiplier\n optionType\n strikePrice\n __typename\n}\n\nfragment UnderlyingSecuritySummary on Security {\n id\n stock {\n name\n primaryExchange\n primaryMic\n symbol\n __typename\n }\n __typename\n}\n\nfragment PositionLeg on PositionLeg {\n security {\n id\n ...SecuritySummary @include(if: \$includeSecurity)\n __typename\n }\n quantity\n positionDirection\n bookValue {\n amount\n currency\n __typename\n }\n totalValue(currencyOverride: \$currencyOverride) {\n amount\n currency\n __typename\n }\n averagePrice {\n amount\n currency\n __typename\n }\n percentageOfAccount\n unrealizedReturns(since: \$since) {\n amount\n currency\n __typename\n }\n marketAveragePrice: averagePrice(currencyOverride: \$currencyOverride) {\n amount\n currency\n __typename\n }\n marketBookValue: bookValue(currencyOverride: \$currencyOverride) {\n amount\n currency\n __typename\n }\n marketUnrealizedReturns: unrealizedReturns(currencyOverride: \$currencyOverride) {\n amount\n currency\n __typename\n }\n oneDayReturnsBaselineV2(currencyOverride: \$currencyOverride) @include(if: \$includeOneDayReturnsBaseline) {\n baseline {\n currency\n amount\n __typename\n }\n useDailyPriceChange\n __typename\n }\n __typename\n}\n\nfragment PositionV2 on PositionV2 {\n id\n quantity\n accounts @include(if: \$includeAccountData) {\n id\n __typename\n }\n percentageOfAccount\n positionDirection\n bookValue {\n amount\n currency\n __typename\n }\n averagePrice {\n amount\n currency\n __typename\n }\n marketAveragePrice: averagePrice(currencyOverride: \$currencyOverride) {\n amount\n currency\n __typename\n }\n marketBookValue: bookValue(currencyOverride: \$currencyOverride) {\n amount\n currency\n __typename\n }\n totalValue(currencyOverride: \$currencyOverride) {\n amount\n currency\n __typename\n }\n unrealizedReturns(since: \$since) {\n amount\n currency\n __typename\n }\n marketUnrealizedReturns: unrealizedReturns(currencyOverride: \$currencyOverride) {\n amount\n currency\n __typename\n }\n security {\n id\n ...SecuritySummary @include(if: \$includeSecurity)\n __typename\n }\n oneDayReturnsBaselineV2(currencyOverride: \$currencyOverride) @include(if: \$includeOneDayReturnsBaseline) {\n baseline {\n currency\n amount\n __typename\n }\n useDailyPriceChange\n __typename\n }\n strategyType\n legs {\n ...PositionLeg\n __typename\n }\n __typename\n}";
3233
};
3334
}
3435

@@ -482,4 +483,32 @@ public function getStatementTransactions(string $account_id, string $period): ar
482483
}
483484
return $transactions;
484485
}
486+
487+
/**
488+
* Retrieve information on specific positions.
489+
*
490+
* @param string[]|NULL $security_ids List of Wealthsimple security ids. NULL will return all owned securities.
491+
* @param string $currency Currency to return the amounts in (CAD or USD).
492+
* @param bool $include_account_data Whether to include account data.
493+
*
494+
* @return object[] A list of positions by account.
495+
* @throws WSApiException
496+
*/
497+
public function getIdentityPositions(?array $security_ids = NULL, string $currency = 'CAD', $include_account_data = TRUE): array {
498+
$positions = $this->doGraphQLQuery(
499+
'FetchIdentityPositions',
500+
[
501+
'identityId' => $this->getTokenInfo()->identity_canonical_id,
502+
'currency' => $currency,
503+
'filter' => ['securityIds' => $security_ids],
504+
'includeAccountData' => $include_account_data
505+
],
506+
'identity.financials.current.positions.edges',
507+
'array',
508+
);
509+
if (!is_array($positions)) {
510+
throw new WSApiException("Unexpected response format to GraphQL query 'FetchIdentityPositions'", 0, $positions);
511+
}
512+
return $positions;
513+
}
485514
}

0 commit comments

Comments
 (0)