Skip to content

Commit

Permalink
Split PnL by security type to match IB performance report
Browse files Browse the repository at this point in the history
  • Loading branch information
rylorin committed May 8, 2024
1 parent 8a0bf52 commit 4de7085
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 15 deletions.
1 change: 1 addition & 0 deletions src/app/components/Portfolio/Report/FeesComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const Fees = ({ theReports, ..._rest }: Props): React.ReactNode => {
{report.year}-{report.month}
</Text>
<Number value={report.feesSummary.totalAmountInBase} width="120px" />
<Spacer />
</HStack>
))}
<HStack borderTop="1px" borderColor="gray.200">
Expand Down
6 changes: 4 additions & 2 deletions src/app/components/Portfolio/Report/PnLsComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ type Props = { theReports: ReportEntry[] };
type PnlCallback = (ReportEntry) => number;

const PnLs: Record<string, PnlCallback> = {
["Equity"]: (tradesSummary: TradesSummary) => tradesSummary.stocksPnLInBase,
["Options"]: (tradesSummary: TradesSummary) => tradesSummary.optionsPnLInBase,
["Stocks"]: (tradesSummary: TradesSummary) => tradesSummary.stocksPnLInBase,
["Equity Options"]: (tradesSummary: TradesSummary) => tradesSummary.optionsPnLInBase,
["Futures"]: (tradesSummary: TradesSummary) => tradesSummary.futuresPnLInBase,
["Futures Options"]: (tradesSummary: TradesSummary) => tradesSummary.fopPnlInBase,
["Bonds"]: (tradesSummary: TradesSummary) => tradesSummary.bondPnLInBase,
};

Expand Down
2 changes: 1 addition & 1 deletion src/bots/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@ export class ITradingBot extends EventEmitter {
const contract_values = {
// Contract part of the option
conId: ibContract.conId!, // eslint-disable-line @typescript-eslint/no-unnecessary-type-assertion
secType: ContractType.Option,
secType: ibContract.secType! as ContractType,
symbol: ibContract.localSymbol!, // eslint-disable-line @typescript-eslint/no-unnecessary-type-assertion
currency: ibContract.currency!, // eslint-disable-line @typescript-eslint/no-unnecessary-type-assertion
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
Expand Down
2 changes: 1 addition & 1 deletion src/models/contract.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const ContractType = {
Bag: "BAG",
Cash: "CASH",
Future: "FUT",
FutureOption: "FOP", // maybe OPT
FutureOption: "FOP",
Index: "IND",
Bond: "BOND",
} as const;
Expand Down
1 change: 1 addition & 0 deletions src/models/option_contract.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export class OptionContract extends Model<
// updatedAt can be undefined during creation
declare updatedAt: CreationOptional<Date>;

/** Base contract part of this option */
@BelongsTo(() => Contract, "id")
declare contract: Contract;

Expand Down
3 changes: 2 additions & 1 deletion src/models/option_statement.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ export class OptionStatement extends Model<
@Column({ type: DataType.SMALLINT, defaultValue: 0 })
declare status: number;

/** related Contract */
/** Base contract part of the option */
declare contract_id: ForeignKey<Contract["id"]>;
@BelongsTo(() => Contract, "contract_id")
declare contract: Contract;
/** Option part of the option */
@BelongsTo(() => OptionContract, "contract_id")
declare option: OptionContract;
}
2 changes: 2 additions & 0 deletions src/routers/reports.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ export type FeesSummary = {
*/
export type TradesSummary = {
stocksPnLInBase: number;
futuresPnLInBase: number;
optionsPnLInBase: number;
fopPnlInBase: number;
bondPnLInBase: number;
totalPnL: number;
};
Expand Down
3 changes: 2 additions & 1 deletion src/routers/statements.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type StatementUnderlyingEntry = {
};

export type StatementUnderlyingOption = StatementUnderlyingEntry & {
// underlying: StatementUnderlyingEntry;
lastTradeDate: string;
strike: number;
callOrPut: OptionType;
Expand All @@ -26,7 +27,7 @@ export type BaseStatement = {
currency: string;
fxRateToBase: number;
amount: number;
// underlying: StatementUnderlyingEntry | undefined;
underlying: StatementUnderlyingEntry | undefined;
trade_id: number | null;
description: string;
};
Expand Down
54 changes: 45 additions & 9 deletions src/routers/statements.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const statementModelToStatementEntry = (item: Statement): Promise<Stateme
fxRateToBase: item.fxRateToBase,
description: item.description,
trade_id: item.trade_unit_id,
underlying: item.stock,
};
switch (item.statementType) {
case StatementTypes.EquityStatement:
Expand All @@ -43,20 +44,36 @@ export const statementModelToStatementEntry = (item: Statement): Promise<Stateme
return OptionStatement.findByPk(item.id, {
include: [
{ model: Contract, as: "contract" },
{ model: OptionContract, as: "option" },
{ model: OptionContract, as: "option" /*, include: [{ model: Contract, as: "underlying" }] */ },
],
}).then((thisStatement) => {
const option: StatementUnderlyingOption = {
id: thisStatement!.contract_id,
secType: ContractType.Option,
id: thisStatement!.option.id,
secType: thisStatement!.contract.secType,
symbol: thisStatement!.contract.symbol,
currency: item.currency,
name: thisStatement!.contract.name,
price: thisStatement!.contract.price,
// underlying: {
// id: thisStatement!.option.stock.id,
// secType: thisStatement!.option.stock.secType,
// symbol: thisStatement!.option.stock.symbol,
// currency: thisStatement!.option.stock.currency,
// name: thisStatement!.option.stock.name,
// price: thisStatement!.option.stock.price,
// },
// underlying: {
// id: item.stock.id,
// secType: item.stock.secType,
// symbol: item.stock.symbol,
// currency: item.stock.currency,
// name: item.stock.name,
// price: item.stock.price,
// },
strike: thisStatement!.option.strike,
lastTradeDate: thisStatement!.option.lastTradeDate,
callOrPut: thisStatement!.option.callOrPut,
multiplier: thisStatement!.option.multiplier,
currency: item.currency,
name: thisStatement!.contract.name,
price: thisStatement!.contract.price,
};
return {
statementType: StatementTypes.OptionStatement,
Expand Down Expand Up @@ -197,7 +214,14 @@ export const prepareReport = (portfolio: Portfolio): Promise<ReportEntry[]> => {
interestsDetails: [],
feesSummary: { totalAmountInBase: 0 },
feesDetails: [],
tradesSummary: { stocksPnLInBase: 0, optionsPnLInBase: 0, bondPnLInBase: 0, totalPnL: 0 },
tradesSummary: {
stocksPnLInBase: 0,
optionsPnLInBase: 0,
futuresPnLInBase: 0,
fopPnlInBase: 0,
bondPnLInBase: 0,
totalPnL: 0,
},
tradesDetails: [],
otherDetails: [],
};
Expand Down Expand Up @@ -262,14 +286,26 @@ export const prepareReport = (portfolio: Portfolio): Promise<ReportEntry[]> => {
break;

case StatementTypes.EquityStatement:
report.tradesSummary.stocksPnLInBase += statement.pnl * statement.fxRateToBase;
switch (statement.underlying.secType) {
case ContractType.Stock:
report.tradesSummary.stocksPnLInBase += statement.pnl * statement.fxRateToBase;
break;
case ContractType.Future:
report.tradesSummary.futuresPnLInBase += statement.pnl * statement.fxRateToBase;
break;
}
report.tradesSummary.totalPnL += statement.pnl * statement.fxRateToBase;
report.tradesDetails.push(statement);
break;

case StatementTypes.OptionStatement:
if (
statement.option.secType == ContractType.FutureOption ||
statement.underlying?.secType == ContractType.Future
)
report.tradesSummary.fopPnlInBase += statement.pnl * statement.fxRateToBase;
else report.tradesSummary.optionsPnLInBase += statement.pnl * statement.fxRateToBase;
report.tradesSummary.totalPnL += statement.pnl * statement.fxRateToBase;
report.tradesSummary.optionsPnLInBase += statement.pnl * statement.fxRateToBase;
report.tradesDetails.push(statement);
break;

Expand Down

0 comments on commit 4de7085

Please sign in to comment.