Skip to content

Commit

Permalink
feat: Holding data calculation on new invest tx
Browse files Browse the repository at this point in the history
  • Loading branch information
letehaha committed Apr 13, 2024
1 parent 6238c34 commit cb20520
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 21 deletions.
35 changes: 23 additions & 12 deletions src/models/investments/Holdings.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ import Security from '@models/investments/Security.model';
* 1. Account has Holdings.
* 2. Holding contains Security name, it's value based on prices, and quantity.
* 3. InvestmentTransaction CRUDs Security inside Holding.
*
* **Notes:**
* 1. No need to store averageCost because we can easily calculate it from by
* using "costBasis / quantity" formula. That way we simply data storage and
* always have up to date value
*/

interface HoldingAttributes {
Expand Down Expand Up @@ -62,13 +67,15 @@ export default class Holding extends Model<HoldingAttributes> {
securityId: number;

/**
* The `value` and `refValue` fields represent the current market value of the specific holding.
* This value is calculated based on the latest available market price of the `security` multiplied by
* the quantity of the security held in the holding. It reflects the present worth of the investment
* in the market. This field is crucial for understanding the real-time monetary worth of the
* investment and plays a key role in portfolio valuation, performance tracking, and making
* informed investment decisions. The value is dynamic and can fluctuate based on market conditions,
* requiring regular updates to ensure accuracy.
* The `value` and `refValue` fields represent the current market value of the
* specific holding.
* This value is calculated based on the latest available market price of the
* `security` multiplied by the quantity of the security held in the holding.
* It reflects the present worth of the investment in the market. This field
* is crucial for understanding the real-time monetary worth of the
* investment and plays a key role in portfolio valuation, performance tracking,
* and making informed investment decisions. The value is dynamic and can
* fluctuate based on market conditions, requiring regular updates to ensure accuracy.
*
* Important:
* It needs to be recalculated every n-time to reflect real value.
Expand All @@ -95,11 +102,15 @@ export default class Holding extends Model<HoldingAttributes> {
quantity: string;

/**
* The `costBasis` field represents the original value or purchase price of an investment in the Holding model.
* It includes the price paid per unit of the security plus any associated expenses like commissions or fees.
* This field is vital for calculating capital gains or losses when the investment is sold and for assessing
* the overall performance of the investment. It also plays a crucial role in determining tax liabilities
* related to capital gains. The cost basis can be adjusted for corporate actions and other financial events.
* The `costBasis` field represents the original value or purchase price of an
* investment in the Holding model.
* It includes the price paid per unit of the security plus any associated
* expenses like commissions or fees.
* This field is vital for calculating capital gains or losses when the
* investment is sold and for assessing the overall performance of the
* investment. It also plays a crucial role in determining tax liabilities
* related to capital gains. The cost basis can be adjusted for corporate
* actions and other financial events.
*
* Example:
* If an investor bought 100 shares of a company at $10 per share, and they paid
Expand Down
4 changes: 2 additions & 2 deletions src/services/calculate-ref-amount.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export async function calculateRefAmount(
quoteCode,
}: BaseParams & { baseCode: string; quoteCode?: string },
attributes: GenericSequelizeModelAttributes,
);
): Promise<number>;
export async function calculateRefAmount(
{
amount,
Expand All @@ -51,7 +51,7 @@ export async function calculateRefAmount(
quoteId,
}: BaseParams & { baseId: number; quoteId?: number },
attributes: GenericSequelizeModelAttributes,
);
): Promise<number>;
export async function calculateRefAmount(
{
amount,
Expand Down
60 changes: 53 additions & 7 deletions src/services/investments/investment-transactions.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import InvestmentTransaction, {
import { calculateRefAmount } from '../calculate-ref-amount.service';
import Security from '@models/investments/Security.model';
import { TRANSACTION_TYPES } from 'shared-types';
import Holding from '@models/investments/Holdings.model';
import SecurityPricing from '@models/investments/SecurityPricing.model';

type CreationParams = Pick<
InvestmentTransaction,
Expand Down Expand Up @@ -73,20 +75,64 @@ export async function createInvestmentTransaction(
)
: params.fees;

console.log('creation-params', {
...creationParams,
amount,
refPrice,
refAmount,
refFees,
});
const result = await InvestmentTransaction.create(
{ ...creationParams, amount, refPrice, refAmount, refFees },
{
transaction,
},
);

const currentPrice = await SecurityPricing.findOne({
where: {
securityId: params.securityId,
},
order: [['date', 'DESC']],
transaction,
});

console.log('currentPrice', currentPrice);

const currentHolding = await Holding.findOne({
where: {
accountId: params.accountId,
securityId: params.securityId,
},
transaction,
});

const newQuantity =
parseFloat(currentHolding.quantity) + parseFloat(params.quantity);
const value = newQuantity * parseFloat(currentPrice.priceClose);
const refValue = await calculateRefAmount(
{
amount: value,
userId,
baseCode: security.currencyCode,
},
{ transaction },
);

await Holding.update(
{
value: String(value),
refValue: String(refValue),
quantity: String(newQuantity),
costBasis: String(parseFloat(currentHolding.costBasis) + amount),
refCostBasis: String(
parseFloat(currentHolding.refCostBasis) + refAmount,
),
},
{
where: {
accountId: params.accountId,
securityId: params.securityId,
},
transaction,
},
);

// TODO: update account balance

if (!isTxPassedFromAbove) {
await transaction.commit();
}
Expand Down

0 comments on commit cb20520

Please sign in to comment.