Skip to content

Commit 4d3cdfb

Browse files
authored
Merge pull request #438 from memplethee-lab/feat/Options
Feat(Feature): Options & Derivatives Contract Module
2 parents e2f1601 + d3e4d31 commit 4d3cdfb

28 files changed

Lines changed: 3996 additions & 0 deletions

src/app.module.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ import { SocialTradingModule } from './social-trading/social-trading.module';
102102
import { TraderProfile } from './social-trading/entities/trader-profile.entity';
103103
import { CopySubscription } from './social-trading/entities/copy-subscription.entity';
104104

105+
// Options & Derivatives (hedging, speculation, pricing)
106+
import { OptionsDerivativesModule } from './options-derivatives/options-derivatives.module';
107+
import { OptionContract } from './options-derivatives/entities/option-contract.entity';
108+
import { OptionPosition } from './options-derivatives/entities/option-position.entity';
109+
import { OptionCollateral } from './options-derivatives/entities/option-collateral.entity';
110+
import { VolatilitySurface } from './options-derivatives/entities/volatility-surface.entity';
111+
105112
// Escrow & Settlement (atomic escrow, refunds, dispute hooks)
106113
import { EscrowSettlementModule } from './escrow-settlement/escrow-settlement.module';
107114
import { EscrowAccount } from './escrow-settlement/entities/escrow-account.entity';
@@ -211,6 +218,11 @@ import { TradingModule } from './trading/trading.module';
211218
MarginPairConfig,
212219
MarginPosition,
213220
MarginInterestAccrual,
221+
// Options & Derivatives
222+
OptionContract,
223+
OptionPosition,
224+
OptionCollateral,
225+
VolatilitySurface,
214226
// Wallet & Payments Integration
215227
WalletLedger,
216228
LedgerEntry,
@@ -266,6 +278,9 @@ import { TradingModule } from './trading/trading.module';
266278

267279
// ── Escrow & Settlement ──
268280
EscrowSettlementModule,
281+
// ── Options & Derivatives ──
282+
OptionsDerivativesModule,
283+
269284
// ── Wallet & Payments Integration ──
270285
WalletModule,
271286
TradingModule,
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { IsInt, IsPositive, IsNumber, Min } from 'class-validator';
2+
3+
export class BuyOptionDto {
4+
@IsInt()
5+
@IsPositive()
6+
contractId: number;
7+
8+
@IsInt()
9+
@IsPositive()
10+
userId: number;
11+
12+
@IsNumber()
13+
@Min(1)
14+
quantity: number;
15+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import {
2+
IsEnum,
3+
IsInt,
4+
IsNumber,
5+
IsOptional,
6+
IsPositive,
7+
Min,
8+
Max,
9+
} from 'class-validator';
10+
import { OptionType } from '../enums/option-type.enum';
11+
import { ExerciseStyle } from '../enums/exercise-style.enum';
12+
13+
export class CreateOptionContractDto {
14+
@IsEnum(OptionType)
15+
optionType: OptionType;
16+
17+
@IsOptional()
18+
@IsEnum(ExerciseStyle)
19+
exerciseStyle?: ExerciseStyle;
20+
21+
@IsInt()
22+
@IsPositive()
23+
underlyingAssetId: number;
24+
25+
@IsNumber()
26+
@IsPositive()
27+
strikePrice: number;
28+
29+
@IsNumber()
30+
@Min(1)
31+
contractSize: number;
32+
33+
@IsOptional()
34+
@IsNumber()
35+
@IsPositive()
36+
underlyingPrice?: number;
37+
38+
/** ISO date string for expiration. */
39+
expirationDate: string;
40+
41+
@IsOptional()
42+
@IsNumber()
43+
@Min(0.01)
44+
@Max(5)
45+
impliedVolatility?: number;
46+
47+
@IsOptional()
48+
@IsNumber()
49+
@Min(0)
50+
@Max(0.25)
51+
riskFreeRate?: number;
52+
53+
/** Number of contracts to mint. */
54+
@IsOptional()
55+
@IsNumber()
56+
@Min(1)
57+
totalSupply?: number;
58+
59+
/** Asset ID for collateral (for writers). */
60+
@IsOptional()
61+
@IsInt()
62+
collateralAssetId?: number;
63+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { IsInt, IsPositive, IsNumber, IsOptional, Min } from 'class-validator';
2+
3+
export class ExerciseOptionDto {
4+
@IsInt()
5+
@IsPositive()
6+
contractId: number;
7+
8+
@IsInt()
9+
@IsPositive()
10+
userId: number;
11+
12+
/** Number of contracts to exercise. */
13+
@IsNumber()
14+
@Min(1)
15+
quantity: number;
16+
17+
/** Current market price of underlying (used for settlement). */
18+
@IsNumber()
19+
@IsPositive()
20+
currentPrice: number;
21+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { IsInt, IsPositive, IsNumber, IsOptional, Min, Max } from 'class-validator';
2+
3+
export class UpdateVolatilityDto {
4+
@IsInt()
5+
@IsPositive()
6+
assetId: number;
7+
8+
@IsNumber()
9+
@IsPositive()
10+
strikePrice: number;
11+
12+
/** ISO date string for expiration. */
13+
expirationDate: string;
14+
15+
@IsNumber()
16+
@Min(0.01)
17+
@Max(10)
18+
impliedVolatility: number;
19+
20+
@IsOptional()
21+
@IsNumber()
22+
bidIv?: number;
23+
24+
@IsOptional()
25+
@IsNumber()
26+
askIv?: number;
27+
28+
@IsOptional()
29+
@IsNumber()
30+
lastTradedIv?: number;
31+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import {
2+
Entity,
3+
PrimaryGeneratedColumn,
4+
Column,
5+
ManyToOne,
6+
JoinColumn,
7+
Index,
8+
CreateDateColumn,
9+
UpdateDateColumn,
10+
} from 'typeorm';
11+
import { OptionContract } from './option-contract.entity';
12+
import { VirtualAsset } from '../../database/entities/virtual-asset.entity';
13+
import { CollateralStatus } from '../enums/collateral-status.enum';
14+
15+
@Entity('option_collaterals')
16+
@Index(['contractId', 'userId'])
17+
@Index(['userId', 'status'])
18+
export class OptionCollateral {
19+
@PrimaryGeneratedColumn()
20+
id: number;
21+
22+
@Column()
23+
@Index()
24+
contractId: number;
25+
26+
@ManyToOne(() => OptionContract)
27+
@JoinColumn({ name: 'contractId' })
28+
contract: OptionContract;
29+
30+
@Column()
31+
@Index()
32+
userId: number;
33+
34+
@Column()
35+
collateralAssetId: number;
36+
37+
@ManyToOne(() => VirtualAsset)
38+
@JoinColumn({ name: 'collateralAssetId' })
39+
collateralAsset: VirtualAsset;
40+
41+
/** Total amount of collateral locked. */
42+
@Column('decimal', { precision: 18, scale: 8 })
43+
lockedAmount: number;
44+
45+
/** Amount still locked (decreases as contracts are exercised/expired). */
46+
@Column('decimal', { precision: 18, scale: 8 })
47+
remainingAmount: number;
48+
49+
/** Number of contracts covered by this collateral. */
50+
@Column('decimal', { precision: 18, scale: 8, default: 0 })
51+
coveredContracts: number;
52+
53+
@Column({ type: 'varchar', default: CollateralStatus.LOCKED })
54+
status: CollateralStatus;
55+
56+
@Column({ nullable: true })
57+
lockedAt: Date;
58+
59+
@Column({ nullable: true })
60+
releasedAt: Date;
61+
62+
@CreateDateColumn()
63+
createdAt: Date;
64+
65+
@UpdateDateColumn()
66+
updatedAt: Date;
67+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import {
2+
Entity,
3+
PrimaryGeneratedColumn,
4+
Column,
5+
ManyToOne,
6+
JoinColumn,
7+
Index,
8+
CreateDateColumn,
9+
UpdateDateColumn,
10+
} from 'typeorm';
11+
import { VirtualAsset } from '../../database/entities/virtual-asset.entity';
12+
import { OptionType } from '../enums/option-type.enum';
13+
import { OptionStatus } from '../enums/option-status.enum';
14+
import { ExerciseStyle } from '../enums/exercise-style.enum';
15+
16+
@Entity('option_contracts')
17+
@Index(['underlyingAssetId', 'expirationDate'])
18+
@Index(['status', 'expirationDate'])
19+
export class OptionContract {
20+
@PrimaryGeneratedColumn()
21+
id: number;
22+
23+
@Column({ type: 'varchar' })
24+
optionType: OptionType;
25+
26+
@Column({ type: 'varchar', default: ExerciseStyle.EUROPEAN })
27+
exerciseStyle: ExerciseStyle;
28+
29+
@Column()
30+
@Index()
31+
underlyingAssetId: number;
32+
33+
@ManyToOne(() => VirtualAsset)
34+
@JoinColumn({ name: 'underlyingAssetId' })
35+
underlyingAsset: VirtualAsset;
36+
37+
/** Strike price in quote asset units. */
38+
@Column('decimal', { precision: 18, scale: 8 })
39+
strikePrice: number;
40+
41+
@Column({ type: 'datetime' })
42+
expirationDate: Date;
43+
44+
/** Contract size = number of underlying units per contract. */
45+
@Column('decimal', { precision: 18, scale: 8, default: 1 })
46+
contractSize: number;
47+
48+
/** Current market price of the underlying at creation. */
49+
@Column('decimal', { precision: 18, scale: 8 })
50+
underlyingPriceAtCreation: number;
51+
52+
/** Option premium per unit. */
53+
@Column('decimal', { precision: 18, scale: 8 })
54+
premium: number;
55+
56+
/** Implied volatility used for pricing (annualized). */
57+
@Column('decimal', { precision: 10, scale: 8, default: 0.3 })
58+
impliedVolatility: number;
59+
60+
/** Risk-free interest rate used for pricing. */
61+
@Column('decimal', { precision: 10, scale: 8, default: 0.05 })
62+
riskFreeRate: number;
63+
64+
/** Delta — option sensitivity to underlying price. */
65+
@Column('decimal', { precision: 10, scale: 8, default: 0 })
66+
delta: number;
67+
68+
/** Gamma — rate of change of delta. */
69+
@Column('decimal', { precision: 10, scale: 8, default: 0 })
70+
gamma: number;
71+
72+
/** Vega — sensitivity to volatility changes. */
73+
@Column('decimal', { precision: 10, scale: 8, default: 0 })
74+
vega: number;
75+
76+
/** Theta — time decay. */
77+
@Column('decimal', { precision: 10, scale: 8, default: 0 })
78+
theta: number;
79+
80+
/** Rho — sensitivity to interest rate changes. */
81+
@Column('decimal', { precision: 10, scale: 8, default: 0 })
82+
rho: number;
83+
84+
/** Total contracts available (initial supply). */
85+
@Column('decimal', { precision: 18, scale: 8, default: 0 })
86+
totalSupply: number;
87+
88+
/** Contracts still outstanding (unsold + unexercised). */
89+
@Column('decimal', { precision: 18, scale: 8, default: 0 })
90+
openInterest: number;
91+
92+
/** Whether option was in-the-money at last check. */
93+
@Column({ default: false })
94+
inTheMoney: boolean;
95+
96+
@Column({ type: 'varchar', default: OptionStatus.ACTIVE })
97+
status: OptionStatus;
98+
99+
@CreateDateColumn()
100+
createdAt: Date;
101+
102+
@UpdateDateColumn()
103+
updatedAt: Date;
104+
}

0 commit comments

Comments
 (0)