Advertisement

#17 Completing Securities Domain Modeling And Updating Our State

In this article we will create the last couple of descriptors that we need before we can create the security category model and the security model itself. Once that is done we will finish up by creating a module for our security states and use it to make adding them to the overall store state very simple.

Territory Model

  • root
    • src
      • store
        • security-territory-model.ts

Creating a territory model is just as simple as creating the other security descriptors that we created in the previous article. We just need to create a class and inherit from the base class (a).

security-territory-model.ts

import { SecurityDescriptor } from "@/store/security-descriptor";

export class SecurityTerritoryModel extends SecurityDescriptor { }
(a) Adding the territory descriptor to our project.

Territory Constants

  • root
    • src
      • store
        • security-constants.ts

Following the pattern next up is to define the constants that represent the text for our initial territories (b).

security-constants.ts

...
export const SECURITY_TERRITORY_DOMESTIC = "Domestic";
export const SECURITY_TERRITORY_INTERNATIONAL = "International";
(b) The initial values for our territory texts.

Territory Types

  • root
    • src
      • store
        • security-types.ts

Now we need to define the interface for our territory state and add it to the overall security state (c).

security-types.ts

...
import { SecurityTerritoryModel } from "@/store/security-territory-model";
...
export interface ISecurityTerritoryModelState {
    index: number;
    items: SecurityTerritoryModel[];
}

export interface ISecurityState {
    ...
    [STATE_SECURITY_TERRITORIES]: ISecurityTerritoryModelState;
}
(c) Specifying the interface for our territory state and adding it to the security state.

Territory Initial State

  • root
    • src
      • store
        • security-territory-initial-state.ts

Creating our initial state for the territories state is exactly the same as we have done in the past. We start by importing the text constants, the model type, and the appropriate state interface. Next we create an empty typed array and a function to create new territories and finish up by adding territories to the array and exporting the state (d).

security-territory-initial-state.ts

import {
    SECURITY_TERRITORY_DOMESTIC,
    SECURITY_TERRITORY_INTERNATIONAL,
} from "@/store/security-constants";
import { SecurityTerritoryModel } from "@/store/security-territory-model";
import { ISecurityTerritoryModelState } from "@/store/security-types";

const territories: SecurityTerritoryModel[] = [];

function createTerritory(id: number, text: string) {
    territories.push(new SecurityTerritoryModel(id, text));
    return id += 1;
}

let index = 1;
index = createTerritory(index, SECURITY_TERRITORY_DOMESTIC);
index = createTerritory(index, SECURITY_TERRITORY_INTERNATIONAL);

export const initialState: ISecurityTerritoryModelState = {
    index,
    items: territories,
};
(d) Creating the initial state for our territories.

Type model

  • root
    • src
      • store
        • security-type-model.ts

Adding a type descriptor (e).

security-type-model.ts

import { SecurityDescriptor } from "@/store/security-descriptor";

export class SecurityTypeModel extends SecurityDescriptor { }
(e) Creating a new type descriptor.

Type constants

  • root
    • src
      • store
        • security-constants.ts

Initially our type descriptor can have three values for the text property (f).

security-constants.ts

export const SECURITY_TYPE_EQUITY = "Equity";
export const SECURITY_TYPE_FIXED_INCOME = "Fixed Income";
export const SECURITY_TYPE_SPECIALTY = "Specialty";
(f) Specifying the possible initial values for the text property of our type descriptor.

Type types (now there's a heading)

  • root
    • src
      • store
        • security-types.ts

Adding the interface and including it in the security state is exactly the same pattern as we have seen previously (g).

security-types.ts

...
import { SecurityTypeModel } from "@/store/security-type-model";
...
export interface ISecurityTypeModelState {
    index: number;
    items: SecurityTypeModel[];
}

export interface ISecurityState {
    ...
    [STATE_SECURITY_TYPES]: ISecurityTypeModelState;
}
(g) Exporting the type model state and adding it to the security state interface.

Type initial state

  • root
    • src
      • store
        • security-type-initial-state.ts

Populating our initial type model state (h).

security-type-initial-state.ts

import {
    SECURITY_TYPE_EQUITY,
    SECURITY_TYPE_FIXED_INCOME,
    SECURITY_TYPE_SPECIALTY,
} from "@/store/security-constants";
import { SecurityTypeModel } from "@/store/security-type-model";
import { ISecurityTypeModelState } from "@/store/security-types";

const types: SecurityTypeModel[] = [];

function createType(id: number, text: string) {
    types.push(new SecurityTypeModel(id, text));
    return id += 1;
}

let index = 1;
index = createType(index, SECURITY_TYPE_EQUITY);
index = createType(index, SECURITY_TYPE_FIXED_INCOME);
index = createType(index, SECURITY_TYPE_SPECIALTY);

export const initialState: ISecurityTypeModelState = {
    index,
    items: types,
};
(h) Creating the data and exporting for the initial security type state.

Category model

  • root
    • src
      • store
        • security-category-model.ts

The category model is our first interesting model in that it is not just a descriptor. The category itself contains three of the descriptors that we have already created (i). To create a category we will need to pass in a configuration object that contains the id values that point to the appropriate descriptor. The descriptors themselves will be initialized to null and we provide several setter methods to set the fields to the corresponding value.

security-category-model.ts

import { SecuritySegmentModel } from "@/store/security-segment-model";
import { SecurityTerritoryModel } from "@/store/security-territory-model";
import { SecurityTypeModel } from "@/store/security-type-model";

export interface ISecurityCategoryModelConfig {
    id: number;
    segmentId: number;
    territoryId: number;
    typeId: number;
}

export class SecurityCategoryModel {
    private _id: number;
    private _segment: SecuritySegmentModel | null = null;
    private _segmentId: number;
    private _territory: SecurityTerritoryModel | null = null;
    private _territoryId: number;
    private _type: SecurityTypeModel | null = null;
    private _typeId: number;

    public get id() { return this._id; }
    public get segment() { return this._segment; }
    public get segmentId() { return this._segmentId; }
    public get territory() { return this._territory; }
    public get territoryId() { return this._territoryId; }
    public get text() {
        const text = { text: "undefined"};
        const territory = (this.territory || text).text;
        const type = (this.type || text).text;
        const segment = (this.segment || text).text;
        return `${territory} ${type} ${segment}`; }
    public get type() { return this._type; }
    public get typeId() { return this._typeId; }

    constructor(config: ISecurityCategoryModelConfig) {
        this._id = config.id;
        this._segmentId = config.segmentId;
        this._territoryId = config.territoryId;
        this._typeId = config.typeId;
    }

    public setSegment = (segment: SecuritySegmentModel) => {
        this._segment = segment;
        return this;
    }

    public setTerritory = (territory: SecurityTerritoryModel) => {
        this._territory = territory;
        return this;
    }

    public setType = (type: SecurityTypeModel) => {
        this._type = type;
        return this;
    }

    public toPersistObj = (): ISecurityCategoryModelConfig => {
        return {
            id: this._id,
            segmentId: this._segmentId,
            territoryId: this._territoryId,
            typeId: this._typeId,
        };
    }
}
(i) Creating the category model which has the main purpose of organizing several of our descriptors into one object.

Category and Security State Constants

  • root
    • src
      • store
        • store-constants.ts

In the last article we added the state constants for our descriptors and now we need to add once for the categories and while we are at it we might as well add one for the securities (j).

store-constants.ts

...
export const STATE_SECURITIES = "STATE_SECURITIES";
export const STATE_SECURITY_CATEGORIES = "STATE_SECURITY_CATEGORIES";
...
(j) Adding constants for the categories and securities.

Category Types

  • root
    • src
      • store
        • security-types.ts

As you can probably guess we need to export an interface for our category state and add it to our security state (k). We are also going to take the opportunity to add a new enum that we will need when defining a security which we will do shortly.

security-types.ts

import {
    STATE_SECURITY_CATEGORIES,
    ...
    STATE_SECURITIES,
    ...
} from "@/store/store-constants";
...
import { SecurityCategoryModel } from "@/store/security-category-model";

export enum SecurityRecommendations {
    Buy,
    Sell,
    Hold,
}

export interface ISecurityCategoryModelState {
    index: number;
    items: SecurityCategoryModel[];
}
...
export interface ISecurityState {
    [STATE_SECURITY_CATEGORIES]: ISecurityCategoryModelState;
    ...
}
(k) Exporting the interface for a category state and adding it to our security state.
Advertisement

Category initial state

  • root
    • src
      • store
        • security-category-initial-state.ts

Although it is a bit more complicated to create the initial state for our categories it follows the same basic pattern (l). Here we see why we took the time to define the the constants for the segments, territories, and types. Since we used the same constants when we created the initial states for all of them we can use the same constants to find individual elements of each now that we need them to create our categories.

security-category-initial-state.ts

import { ISecurityCategoryModelConfig, SecurityCategoryModel } from "@/store/security-category-model";
import { ISecurityCategoryModelState } from "@/store/security-types";

import {
    SECURITY_SEGMENT_DEVELOPED_TEXT,
    SECURITY_SEGMENT_EMERGING_TEXT,
    SECURITY_SEGMENT_LARGE_CAP_TEXT,
    SECURITY_SEGMENT_MID_CAP_TEXT,
    SECURITY_SEGMENT_SMALL_CAP_TEXT,
    SECURITY_TERRITORY_DOMESTIC,
    SECURITY_TERRITORY_INTERNATIONAL,
    SECURITY_TYPE_EQUITY,
    SECURITY_TYPE_FIXED_INCOME,
    SECURITY_TYPE_SPECIALTY,
} from "@/store/security-constants";

import { initialState as segments } from "@/store/security-segment-initial-state";
import { initialState as territories } from "@/store/security-territory-initial-state";
import { initialState as types } from "@/store/security-type-initial-state";

const largeCap = segments.items.find((x) => x.text === SECURITY_SEGMENT_LARGE_CAP_TEXT)!;
const midCap = segments.items.find((x) => x.text === SECURITY_SEGMENT_MID_CAP_TEXT)!;
const smallCap = segments.items.find((x) => x.text === SECURITY_SEGMENT_SMALL_CAP_TEXT)!;
const developed = segments.items.find((x) => x.text === SECURITY_SEGMENT_DEVELOPED_TEXT)!;
const emerging = segments.items.find((x) => x.text === SECURITY_SEGMENT_EMERGING_TEXT)!;

const domestic = territories.items.find((x) => x.text === SECURITY_TERRITORY_DOMESTIC)!;
const international = territories.items.find((x) => x.text === SECURITY_TERRITORY_INTERNATIONAL)!;

const equity = types.items.find((x) => x.text === SECURITY_TYPE_EQUITY)!;
const fixedIncome = types.items.find((x) => x.text === SECURITY_TYPE_FIXED_INCOME)!;
const specialty = types.items.find((x) => x.text === SECURITY_TYPE_SPECIALTY)!;

const categories: SecurityCategoryModel[] = [];

function createCategory(config: ISecurityCategoryModelConfig) {
    categories.push(new SecurityCategoryModel(config));
    return config.id += 1;
}

let index = 1;
index = createCategory({ id: index, segmentId: largeCap.id, territoryId: domestic.id, typeId: equity.id });
index = createCategory({ id: index, segmentId: midCap.id, territoryId: domestic.id, typeId: equity.id });
index = createCategory({ id: index, segmentId: smallCap.id, territoryId: domestic.id, typeId: equity.id });
index = createCategory({ id: index, segmentId: developed.id, territoryId: international.id, typeId: equity.id });
index = createCategory({ id: index, segmentId: emerging.id, territoryId: international.id, typeId: equity.id });
index = createCategory({ id: index, segmentId: developed.id, territoryId: domestic.id, typeId: fixedIncome.id });
index = createCategory({ id: index, segmentId: developed.id, territoryId: international.id, typeId: fixedIncome.id });
index = createCategory({ id: index, segmentId: developed.id, territoryId: domestic.id, typeId: specialty.id });

export const initialState: ISecurityCategoryModelState = {
    index,
    items: categories,
};
(l) Creating the initial state for our categories.

Security Model

  • root
    • src
      • store
        • security-model.ts

That last model that we should need for a little while is our security model (m). This model is a little less complicated than the category in that it only contains one descriptor and a category. Again we start by passing the configuration object into the constructor which contains only values for the scalar properties. We then also add the appropriate setter methods.

security-model.ts

import { SecurityCategoryModel } from "@/store/security-category-model";
import { SecurityMarketModel } from "@/store/security-market-model";
import { SecurityRecommendations } from "@/store/security-types";

export interface ISecurityModelConfig {
    categoryId: number;
    id: number;
    last: number;
    marketId: number;
    recommendation: SecurityRecommendations;
    symbol: string;
}

export class SecurityModel {
    private _category: SecurityCategoryModel | null = null;
    private _categoryId: number;
    private _id: number;
    private _last: number;
    private _market: SecurityMarketModel | null = null;
    private _marketId: number;
    private _recommendation: SecurityRecommendations;
    private _symbol: string;

    public get category() { return this._category; }
    public get categoryId() { return this._categoryId; }
    public get id() { return this._id; }
    public get last() { return this._last; }
    public get market() { return this._market; }
    public get marketId() { return this._marketId; }
    public get recommendation() { return this._recommendation; }
    public get symbol() { return this._symbol; }

    constructor(config: ISecurityModelConfig) {
        this._categoryId     = config.categoryId;
        this._id             = config.id;
        this._last           = config.last;
        this._marketId       = config.marketId;
        this._recommendation = config.recommendation;
        this._symbol         = config.symbol;
    }

    public setCategory = (category: SecurityCategoryModel) => {
        this._category = category;
        return this;
    }

    public setMarket = (market: SecurityMarketModel) => {
        this._market = market;
        return this;
    }

    public toPersistObj = (): ISecurityModelConfig => {
        return {
            categoryId: this._categoryId,
            id: this._id,
            last: this._last,
            marketId: this._marketId,
            recommendation: this._recommendation,
            symbol: this._symbol,
        };
    }
}
(m) Defining our security model.

Security Types

  • root
    • src
      • store
        • security-types.ts

Back to our security types file to export the security model interface and add it to the overall state (n).

security-types.ts

...
import { SecurityModel } from "@/store/security-model";
...
export interface ISecurityModelState {
    index: number;
    items: SecurityModel[];
}
...
export interface ISecurityState {
    ...
    [STATE_SECURITIES]: ISecurityModelState;
    ...
}
(n) Exporting the security model interface and adding it to the security state.

Security Initial State

  • root
    • src
      • store
        • security-model-initial-state.ts

Just as before we need to create some data for our initial state (o).

security-model-initial-state.ts

import { ISecurityModelConfig, SecurityModel } from "@/store/security-model";
import { ISecurityModelState, SecurityRecommendations } from "@/store/security-types";

import {
    SECURITY_MARKET_CBOE,
    SECURITY_MARKET_NASDAQ,
    SECURITY_MARKET_NYSE,
} from "@/store/security-constants";

import { initialState as categories } from "@/store/security-category-initial-state";
import { initialState as markets } from "@/store/security-market-initial-state";

const buy = SecurityRecommendations.Buy;
const hold = SecurityRecommendations.Hold;
const sell = SecurityRecommendations.Sell;

const delc = categories.items[0];
const demc = categories.items[1];
const desc = categories.items[2];
const iedm = categories.items[3];
const ieem = categories.items[4];
const fid = categories.items[5];
const fii = categories.items[6];
const spec = categories.items[7];

const cboe = markets.items.find((x) => x.text === SECURITY_MARKET_CBOE)!;
const nasdaq = markets.items.find((x) => x.text === SECURITY_MARKET_NASDAQ)!;
const nyse = markets.items.find((x) => x.text === SECURITY_MARKET_NYSE)!;

const securities: SecurityModel[] = [];

function createSecurity(id: number, config: Omit<ISecurityModelConfig, "id">) {
    securities.push(new SecurityModel({ id, ...config }));
    return id += 1;
}

const acwv = { categoryId: delc.id, last: 90.27, marketId: cboe.id, recommendation: buy, symbol: "ACWV" };
const bnd = { categoryId: fid.id, last: 83.84, marketId: nyse.id, recommendation: hold, symbol: "BND" };
const bndx = { categoryId: fii.id, last: 58.27, marketId: nasdaq.id, recommendation: buy, symbol: "BNDX" };
const embh = { categoryId: fii.id, last: 24.43, marketId: nyse.id, recommendation: hold, symbol: "EMBH" };
const esgd = { categoryId: iedm.id, last: 60.89, marketId: nasdaq.id, recommendation: hold, symbol: "ESGD" };
const fnde = { categoryId: iedm.id, last: 26.55, marketId: nyse.id, recommendation: buy, symbol: "FNDE" };
const ftec = { categoryId: spec.id, last: 59.49, marketId: nyse.id, recommendation: buy, symbol: "FTEC" };
const lkor = { categoryId: fid.id, last: 56.05, marketId: nasdaq.id, recommendation: hold, symbol: "LKOR" };
const mdyg = { categoryId: demc.id, last: 52.31, marketId: nyse.id, recommendation: sell, symbol: "MDYG" };
const mgk = { categoryId: delc.id, last: 126.26, marketId: nyse.id, recommendation: hold, symbol: "MGK" };
const mlqd = { categoryId: fid.id, last: 51.73, marketId: cboe.id, recommendation: buy, symbol: "MLQD" };
const pcy = { categoryId: fii.id, last: 29.06, marketId: nyse.id, recommendation: hold, symbol: "PCY" };
const qemm = { categoryId: ieem.id, last: 54.64, marketId: nyse.id, recommendation: hold, symbol: "QEMM" };
const schg = { categoryId: delc.id, last: 79.76, marketId: nyse.id, recommendation: buy, symbol: "SCHG" };
const slyg = { categoryId: desc.id, last: 58.70, marketId: nyse.id, recommendation: sell, symbol: "SLYG" };
const vbk = { categoryId: desc.id, last: 179.79, marketId: nyse.id, recommendation: buy, symbol: "VBK" };
const vea = { categoryId: iedm.id, last: 39.35, marketId: nyse.id, recommendation: hold, symbol: "VEA" };
const vis = { categoryId: spec.id, last: 139.01, marketId: nyse.id, recommendation: buy, symbol: "VIS" };
const vot = { categoryId: demc.id, last: 143.52, marketId: nyse.id, recommendation: buy, symbol: "VOT" };
const vwo = { categoryId: ieem.id, last: 39.10, marketId: nyse.id, recommendation: hold, symbol: "VWO" };
const xcem = { categoryId: ieem.id, last: 24.48, marketId: nyse.id, recommendation: hold, symbol: "XCEM" };
const xsoe = { categoryId: ieem.id, last: 26.64, marketId: nyse.id, recommendation: hold, symbol: "XSOE" };

let index = 1;
index = createSecurity(index, acwv);
index = createSecurity(index, bnd);
index = createSecurity(index, bndx);
index = createSecurity(index, embh);
index = createSecurity(index, esgd);
index = createSecurity(index, fnde);
index = createSecurity(index, ftec);
index = createSecurity(index, lkor);
index = createSecurity(index, mdyg);
index = createSecurity(index, mgk);
index = createSecurity(index, mlqd);
index = createSecurity(index, pcy);
index = createSecurity(index, qemm);
index = createSecurity(index, schg);
index = createSecurity(index, slyg);
index = createSecurity(index, vbk);
index = createSecurity(index, vea);
index = createSecurity(index, vis);
index = createSecurity(index, vot);
index = createSecurity(index, vwo);
index = createSecurity(index, xcem);
index = createSecurity(index, xsoe);

export const initialState: ISecurityModelState = {
    index,
    items: securities,
};
(o) Creating the initial state for the security models.

Exporting the models

  • root
    • src
      • store
        • index.ts

With them all defined we can just export them all at one time (p).

index.ts

...
export * from "@/store/security-category-model";
export * from "@/store/security-market-model";
export * from "@/store/security-model";
export * from "@/store/security-segment-model";
export * from "@/store/security-territory-model";
export * from "@/store/security-type-model";
...
(p) Exporting the models for easier importing later.

Extending the store state

  • root
    • src
      • store
        • store-types.ts

Since we have already created an interface that represents all the security models we can use it to extend our store state (q).

store-types.ts

...
import { ISecurityState } from "@/store/security-types";

export interface IStoreState extends ISecurityState {
    ...
}
...
(q) Extending the store state using the security state interface.

Security Module

  • root
    • src
      • store
        • security-module.ts

Just like with our accounts and routes we will create a new file that will define the module for the security states that we have just created (r).

security-module.ts

import {
    STATE_SECURITIES,
    STATE_SECURITY_CATEGORIES,
    STATE_SECURITY_MARKETS,
    STATE_SECURITY_SEGMENTS,
    STATE_SECURITY_TERRITORIES,
    STATE_SECURITY_TYPES,
} from "@/store/store-constants";

import { ISecurityState } from "@/store/security-types";

import { initialState as categoryState } from "@/store/security-category-initial-state";
import { initialState as marketState } from "@/store/security-market-initial-state";
import { initialState as securityState } from "@/store/security-model-initial-state";
import { initialState as segmentState } from "@/store/security-segment-initial-state";
import { initialState as territoryState } from "@/store/security-territory-initial-state";
import { initialState as typeState } from "@/store/security-type-initial-state";

export const securitiesState: ISecurityState = {
    [STATE_SECURITIES]: securityState,
    [STATE_SECURITY_CATEGORIES]: categoryState,
    [STATE_SECURITY_MARKETS]: marketState,
    [STATE_SECURITY_SEGMENTS]: segmentState,
    [STATE_SECURITY_TERRITORIES]: territoryState,
    [STATE_SECURITY_TYPES]: typeState,
};
(r) Exporting the securities state object.

Adding the security state to the store

  • root
    • src
      • store
        • store.ts

Adding all of the security states to our store state is once again a simple use of the spread operator away (s).

store.ts

...
import {
    securitiesState,
} from "@/store/security-module";
...
const state: IStoreState = {
    ...
    ...securitiesState,
};
...
(s) Using the spread operator to add the security states to our store state.
Exciton Interactive LLC
Advertisement