Releases: TimelordUK/jspurefix
Releases · TimelordUK/jspurefix
Importing as external module - Index.ts
https://github.com/TimelordUK/jspurefix/issues/1
now install jspurefix
and import types such as below
import { AsciiSession, MsgView, IJsFixConfig, IJsFixLogger, MsgType, MsgTag } from 'jspurefix'
import { SessionRejectReason, SubscriptionRequestType, TradeRequestStatus, ITradeCaptureReport, ITradeCaptureReportRequest } from 'jspurefix/dist/types/FIX4.4/repo'
// interfaces generated by compiler to make messages easy in an IDE
import { TradeFactory } from './trade-factory'
export class TradeCaptureServer extends AsciiSession {
private readonly logger: IJsFixLogger
private readonly fixLog: IJsFixLogger
private readonly tradeFactory: TradeFactory = new TradeFactory()
private timerHandle: NodeJS.Timer = null
constructor (public readonly config: IJsFixConfig) {
super(config)
this.logReceivedMsgs = true
this.logger = config.logFactory.logger(`${this.me}:TradeCaptureServer`)
this.fixLog = config.logFactory.plain(`jsfix.${config!.description!.application!.name}.txt`)
}
protected onApplicationMsg (msgType: string, view: MsgView): void {
this.logger.info(`${view.toJson()}`)
switch (msgType) {
case MsgType.TradeCaptureReportRequest: {
this.tradeCaptureReportRequest(view.toObject())
break
}
default: {
const seqNum = view.getTyped(MsgTag.MsgSeqNum)
this.send(msgType, this.config.factory.reject(msgType, seqNum, `${this.me}: unexpected msg type '${msgType}'`, SessionRejectReason.InvalidMsgType))
break
}
}
}
protected onReady (view: MsgView): void {
// server waits for client to make a request
this.logger.info('ready for requests.')
}
protected onStopped (): void {
this.logger.info('stopped')
if (this.timerHandle) {
clearInterval(this.timerHandle)
}
}
protected onLogon (view: MsgView, user: string, password: string): boolean {
return true
}
// use msgType for example to persist only trade capture messages to database
protected onDecoded (msgType: string, txt: string): void {
this.fixLog.info(txt)
}
// no delimiter substitution on transmit messages
protected onEncoded (msgType: string, txt: string): void {
this.fixLog.info(AsciiSession.asPiped(txt))
}
private tradeCaptureReportRequest (tcr: ITradeCaptureReportRequest): void {
this.logger.info(`received tcr ${tcr.TradeRequestID}`)
// send back an ack.
this.send(MsgType.TradeCaptureReportRequestAck, TradeFactory.tradeCaptureReportRequestAck(tcr, TradeRequestStatus.Accepted))
// send some trades
const batch: ITradeCaptureReport[] = this.tradeFactory.batchOfTradeCaptureReport()
batch.forEach((tc: ITradeCaptureReport) => {
this.send(MsgType.TradeCaptureReport, tc)
})
this.send(MsgType.TradeCaptureReportRequestAck, TradeFactory.tradeCaptureReportRequestAck(tcr, TradeRequestStatus.Completed))
// start sending the odd 'live' trade
switch (tcr.SubscriptionRequestType) {
case SubscriptionRequestType.SnapshotAndUpdates: {
this.timerHandle = setInterval(() => {
if (Math.random() < 0.4) {
const tc: ITradeCaptureReport = this.tradeFactory.singleTradeCaptureReport()
this.send(MsgType.TradeCaptureReport, tc)
}
}, 5000)
break
}
}
}
}
README / Unit Test
- slightly reword README description
- add unit test for dot notation nested fetch
test('nested view fetch' , () => {
const legGrpView = view.getView('InstrmtLegGrp.NoLegs')
expect(legGrpView).toBeTruthy()
const legGrp: IInstrumentLeg[] = legGrpView.toObject()
expect(legGrp).toBeTruthy()
expect(Array.isArray(legGrp))
expect(legGrp.length).toEqual(2)
})
FIXML sample application
this release fixes compiled fixml interfaces where previously certain fields were not named correctly due to collisions in their abbreviations. An INewSingleOrder should be equivalent whether compiling from fixml or from repo based definitions.
also included is a simple demo app run with npm run http-oms which shows how fximl over http can be used. The message below shows how an object in javascript is rendered into FIXML notation.
public createOrder (symbol: string, side: Side, qty: number, price: number): INewOrderSingle {
const id: number = this.id++
return {
ClOrdID: `Cli${id}`,
Account: this.account,
Side: side,
Price: price,
OrdType: OrdType.Limit,
OrderQtyData: {
OrderQty: qty
} as IOrderQtyData,
Instrument: {
Symbol: symbol,
SecurityID: '459200101',
SecurityIDSource: SecurityIDSource.IsinNumber
} as IInstrument,
TimeInForce: TimeInForce.GoodTillCancelGtc
} as INewOrderSingle
}
<FIXML>
<Order ID="Cli1" Acct="TradersRUs" Side="1" Typ="2" Px="100.12" TmInForce="1">
<Hdr SID="accept-comp" TID="init-comp" SSub="user123" TSub="INC"/>
<Instrmt Sym="IBM" ID="459200101" Src="4"/>
<OrdQty Qty="10000"/>
</Order>
</FIXML>
public fillOrder (order: INewOrderSingle): IExecutionReport {
const id: number = this.execId++
return {
ClOrdID: order.ClOrdID,
OrdType: order.OrdType,
TransactTime: new Date(),
AvgPx: order.Price,
LeavesQty: 0,
LastPx: order.Price,
ExecType: ExecType.OrderStatus,
OrdStatus: OrdStatus.Filled,
ExecID: `exec${id}`,
Side: order.Side,
Price: order.Price,
OrderQtyData: {
OrderQty: order.OrderQtyData.OrderQty
} as IOrderQtyData,
Instrument: {
Symbol: order.Instrument.Symbol,
SecurityID: order.Instrument.SecurityID,
SecurityIDSource: SecurityIDSource.IsinNumber
} as IInstrument
} as IExecutionReport
}
the fixml is sent back to the client :-
<FIXML>
<ExecRpt ID="Cli1" ExecID="exec1" ExecTyp="I" Stat="2" Side="1" Typ="2" Px="100.12" LastPx="100.12" LeavesQty="0" AvgPx="100.12" TxnTm="2018-10-07T12:16:12.584">
<Hdr SID="accept-comp" TID="init-comp" TSub="fix"/>
<Instrmt Sym="IBM" ID="459200101" Src="4"/>
<OrdQty Qty="10000"/>
</ExecRpt>
</FIXML>