· 9 years ago · Dec 15, 2016, 02:05 PM
1#!/usr/bin/perl
2#
3#
4# ACTUAL PNL calculation script by Herman Hung
5#
6# Please note, this script is expected to be run every day, without fail,
7# after the transitions to backfill.
8#
9#
10
11use strict;
12use Sys::Syslog qw(:DEFAULT setlogsock);
13use Getopt::Long;
14use DBI;
15use Mail::Sender;
16use Date::Business;
17use File::Copy;
18use YAML::Tiny;
19
20use IO::Handle;
21
22use Class::Struct;
23use Scalar::Util;
24use List::Util qw(first max maxstr min minstr reduce shuffle sum);
25
26use DateTime;
27
28use Test::More;
29
30use Time::HiRes qw( usleep ualarm gettimeofday tv_interval time );
31use POSIX qw( strftime );
32
33my $debugmode = 0;
34my $testwritemode = 0;
35
36my $mailsender = new Mail::Sender {
37 from => 'bluemin@bluefirecap.com',
38 smtp => 'mail.bluefirecap.com'}
39 or die "$Mail::Sender::Error\n";
40
41# Define a Position Structure
42struct TradePosition => {
43 positionid => '$',
44 origmsgid => '$',
45 timestring => '$',
46 positionpx => '$',
47 origqty => '$',
48 leavesqty => '$',
49 client => '$',
50 account => '$',
51 symbol => '$',
52 side => '$',
53 endpoint => '$',
54 prodmultiplier => '$',
55 xchangerate => '$',
56 origclient => '$',
57 clearcharge => '$',
58 exchangecharge => '$',
59 liquiditycharge => '$',
60 seccharge => '$',
61 nfacharge => '$',
62 bfexorigqtys => '@',
63 bfexsizes => '@',
64 bfexprices => '@',
65 bfexposids => '@',
66 bfexorigids => '@',
67 bfexclearcharges => '@',
68 bfexexchangecharges => '@',
69 bfexliquiditycharges => '@',
70 bfexseccharges => '@',
71 bfexnfacharges => '@',
72 bfexorigclients => '@',
73 bfexxchangerates => '@',
74 bfexendpoints => '@',
75 #bfexdates => '@',
76 #positiondate => '$',
77};
78
79########################################################################
80# Initial print
81########################################################################
82
83print "===========================================\n";
84print "Loading up PNL Actualization script!\n";
85print "===========================================\n";
86
87########################################################################
88# Date Variables
89my $tminusonedatadate; # Date for formatting
90my $tminusoneymd; # String used for querying against data for T-1
91my $todaysymd;
92my $todaysdatadate;
93my $tminustwoymd;
94my $tminustwodatadate;
95
96# Write these fills if we've read them all
97my @fillwritestrings = ();
98
99# Position Map variables
100my %openlongpositionbyclientsymbol = (); # Hash of arrays of open long positions by client/symbol combination
101my %openshortpositionbyclientsymbol = (); # Hash of arrays of open short positions by client/symbol combination
102
103# Marks Map For Real Time Run
104my %marksmap = ();
105
106# PNL Map Variables
107my %closedpnlbyclientsymbol = ();
108my %totalfeebyclientsymbol = ();
109
110# Storage maps, which is kind of annoying, but necessary
111my %casedaypnl = ();
112my %caseclearfeepnl = ();
113my %caseexfeepnl = ();
114my %caseliqfeepnl = ();
115my %casesecfeepnl = ();
116my %casenfafeepnl = ();
117my %casepositionpnl = ();
118
119# Determine which CASE combinations we have to go through
120my %caseiterationmap = ();
121
122# Internal Cross Variables
123my %openlongintexbysymbol = ();
124my %openshortintexbysymbol = ();
125
126# Debt queue
127my @debtqueue = ();
128
129# Map of ledger IDs to ignore.
130my %ignoreids = ();
131
132# Array of BFEX action strings
133my @bfexactions = ();
134
135# Map of ledger mods
136my %ledgerqtymodactions = ();
137my @currentledgeractions = ();
138my @ledgeractionstowrite = ();
139
140########################################################################
141# Get options
142my ($opt_help,$opt_date,$opt_runmode,$opt_mail,$opt_config,$opt_write,$opt_quiet,$opt_fillsfromdatabase,$opt_dontinsertpnltodb,$opt_posteodstart,$opt_debug,$opt_dateoffset,$opt_testmode);
143
144########################################################################
145
146 GetOptions(
147 "date=s" => \$opt_date,
148 "runmode=s" => \$opt_runmode,
149 "fillsfromdb" => \$opt_fillsfromdatabase,
150 "nodbpnlinsert" => \$opt_dontinsertpnltodb,
151 "posteodstart" => \$opt_posteodstart,
152 "dateoffset=s" => \$opt_dateoffset,
153 "debug" => \$opt_debug,
154 "test" => \$opt_testmode,
155 "help|?" => \$opt_help)
156 or pod2usage(1);
157
158########################################################################
159# Check for Debug Mode
160if($opt_debug) {
161 $debugmode = 1;
162}
163
164# Check for Test Mode -- Writing Test Files
165if($opt_testmode) {
166 $testwritemode = 1;
167}
168
169# Write Destination for Real Time PNL
170my $rtpnlwritefile;
171
172if($testwritemode) {
173 $rtpnlwritefile = "test_acste_pnl_actual.txt";
174}
175else {
176 $rtpnlwritefile = "/datlib/reportviews/vw141.3/acste_pnl_actual.txt";
177}
178
179########################################################################
180# Calculate today's date
181if ($opt_date) {
182 # Assume format of yyyyMMdd
183 my $yearstr = substr $opt_date, 0, 4;
184 my $monthstr = substr $opt_date, 4, 2;
185 my $daystr = substr $opt_date, 6, 2;
186
187 $todaysdatadate = DateTime->new(
188 year => $yearstr,
189 month => $monthstr,
190 day => $daystr,
191 hour => 18,
192 minute => 0,
193 second => 0,
194 nanosecond => 0,
195 time_zone => 'America/Chicago');
196 $tminusonedatadate = $todaysdatadate;
197 $tminusonedatadate->subtract(days => 1);
198
199 # Set the variables
200 $todaysymd = $opt_date;
201 $tminusoneymd = $tminusonedatadate->ymd;
202 $tminusoneymd =~ s/-//g;
203
204 print "DATE OPTION HAS BEEN PASSED--->\n" unless ($opt_quiet);
205 print "Today's date: $todaysymd\n";
206 print "Yesterday's date: $tminusoneymd\n";
207}
208elsif($opt_dateoffset){
209 $todaysdatadate = DateTime->now(time_zone => 'America/Chicago');
210
211 if($opt_dateoffset > 0) {
212 # Start execution as if this is "tomorrow"
213 $todaysdatadate->add(days => $opt_dateoffset);
214 }
215 elsif($opt_dateoffset < 0) {
216 $opt_dateoffset = abs($opt_dateoffset);
217 $todaysdatadate->subtract(days => $opt_dateoffset);
218 }
219
220 $todaysymd = $todaysdatadate->ymd;
221 $todaysymd =~ s/-//g;
222 $tminusonedatadate = $todaysdatadate;
223 $tminusonedatadate->subtract(days => 1);
224 $tminusoneymd = $tminusonedatadate->ymd;
225 $tminusoneymd =~ s/-//g;
226
227 print "DATE OPTION HAS NOT BEEN PASSED--->\n" unless ($opt_quiet);
228 print "Today's date: $todaysymd\n";
229 print "Yesterday's date: $tminusoneymd\n";
230}
231else {
232 $todaysdatadate = DateTime->now(time_zone => 'America/Chicago');
233
234 if($opt_posteodstart) {
235 # Start execution as if this is "tomorrow"
236 $todaysdatadate->add(days => 1);
237 }
238
239 $todaysymd = $todaysdatadate->ymd;
240 $todaysymd =~ s/-//g;
241 $tminusonedatadate = $todaysdatadate;
242 $tminusonedatadate->subtract(days => 1);
243 $tminusoneymd = $tminusonedatadate->ymd;
244 $tminusoneymd =~ s/-//g;
245
246 print "DATE OPTION HAS NOT BEEN PASSED--->\n" unless ($opt_quiet);
247 print "Today's date: $todaysymd\n";
248 print "Yesterday's date: $tminusoneymd\n";
249}
250
251########################################################################
252# Runmode calculation
253########################################################################
254my $runmode;
255print "Scanning for script running mode!\n";
256if($opt_runmode) {
257 if($opt_runmode eq "FullDayCalc") {
258 print "Calculation mode detected! Starting pull for previous day's data!\n";
259 $runmode = "FullDayCalc";
260 }
261 elsif ($opt_runmode eq "RealTime") {
262 print "RealTime mode detected! Starting pull from pnlfills!\n";
263 $runmode = "RealTime";
264 }
265 else {
266 print "Invalid script run mode detected: $opt_runmode! Valid modes are FullDayCalc or RealTime! Aborting!\n";
267 die "Invalid script run mode detected: $opt_runmode! Valid modes are FullDayCalc or RealTime! Aborting!\n";
268 }
269}
270else {
271 $runmode = "FullDayCalc";
272 print "No run mode parameter detected! Defaulting to calculations / insertions for previous day!\n";
273}
274
275########################################################################
276# Initialization of output file
277########################################################################
278
279my $outfile = "/datlib/actualpnl/results." . $todaysymd . ".out";
280if($testwritemode) {
281 $outfile= "testresults." . $todaysymd . ".out";
282}
283
284if($opt_runmode eq "RealTime") {
285 $outfile = "/datlib/actualpnl/rtresults." . $todaysymd . ".out";
286 if($testwritemode) {
287 $outfile= "testrtresults." . $todaysymd . ".out";
288 }
289
290}
291
292open(PRINTERFILE, ">" , "$outfile") || print "Failed to open file for writing today's output at $outfile!\n";
293PRINTERFILE->autoflush;
294
295########################################################################
296# Attempt to load up ledger file for the day
297########################################################################
298
299my $ledgerfile = "/datlib/actualpnl/ledger." . $todaysymd . ".out";
300PrintOutStd("Attempting to load ledger archive from $ledgerfile!\n");
301my $ledgerfilefound = 1;
302open(EXISTINGLEDGERFILE, "$ledgerfile") || ($ledgerfilefound = 0);
303EXISTINGLEDGERFILE->autoflush;
304
305if(!$ledgerfilefound) {
306 PrintOutStd("No accounting ledger file detected for tradedate $todaysymd. We will write in all ledger actions for the day!\n");
307}
308else {
309 # Retrieve the accounting ledger. We should have all the same
310 # strings that we would normally process for ledger actions.
311 while(<EXISTINGLEDGERFILE>) {
312 my $ledgerline = $_;
313 push(@currentledgeractions, $ledgerline);
314 }
315
316 # Push the ledger actions into existence
317 TakeAllLedgerActions();
318}
319
320########################################################################
321# Load up previous days' open positions, regardless of run mode
322# Format should be <TMPOSITION>,<Client>,<Symbol>,Price,Size (negative if short)
323PrintOut("==========================================\n");
324my $filetoopen = "/datlib/actualpnl/positions." . $tminusoneymd . ".out";
325open(POSITIONSFILE, "$filetoopen") || print "Failed to find file for previous day's position at $filetoopen!\n";
326POSITIONSFILE->autoflush;
327
328# Read the positions into a positions map
329# Format is:
330# print ARCHIVEFILE "$timestring,$positionid,$origid,$positionpx,$origqty,$leavesqty,$client,$symbol,$side,$endpoint,$origclient,$prodmultiplier,$xchangerate\n";
331PrintOutStd("Attempting to retrieve positions (there may not be any) from $filetoopen\n");
332while(<POSITIONSFILE>) {
333 # Pick up info from the positions file
334 my @linearray = split(/,/);
335 my $timestamp = $linearray[0];
336 my $positionid = $linearray[1];
337 my $origid = $linearray[2];
338 my $positionpx = $linearray[3];
339 my $origqty = $linearray[4];
340 my $leavesqty = $linearray[5];
341 my $client = $linearray[6];
342 my $symbol = $linearray[7];
343 my $side = $linearray[8];
344 my $endpoint = $linearray[9];
345 my $origclient= $linearray[10];
346 my $prodmultiplier = $linearray[11];
347 my $xchangerate = $linearray[12];
348 my $account = $linearray[13];
349 my $clearcharge = $linearray[14];
350 my $exchangecharge = $linearray[15];
351 my $liquiditycharge = $linearray[16];
352 my $seccharge = $linearray[17];
353 my $nfacharge = $linearray[18];
354 my $posdate = $linearray[19];
355
356 # Inject positions into maps from retrieval
357 my $insertposition = new TradePosition;
358 $insertposition->positionid($positionid);
359 $insertposition->origmsgid($origid);
360 $insertposition->timestring($timestamp);
361 $insertposition->positionpx($positionpx);
362 $insertposition->origqty($origqty);
363 $insertposition->leavesqty($leavesqty);
364 $insertposition->client($client);
365 $insertposition->account($account);
366 $insertposition->symbol($symbol);
367 $insertposition->side($side);
368 $insertposition->endpoint($endpoint);
369 $insertposition->prodmultiplier($prodmultiplier);
370 $insertposition->xchangerate($xchangerate);
371 $insertposition->origclient($origclient);
372 $insertposition->clearcharge($clearcharge);
373 $insertposition->exchangecharge($exchangecharge);
374 $insertposition->liquiditycharge($liquiditycharge);
375 $insertposition->seccharge($seccharge);
376 $insertposition->nfacharge($nfacharge);
377 $insertposition->bfexorigqtys(());
378 $insertposition->bfexsizes(());
379 $insertposition->bfexprices(());
380 $insertposition->bfexposids(());
381 $insertposition->bfexorigids(());
382 $insertposition->bfexclearcharges(());
383 $insertposition->bfexexchangecharges(());
384 $insertposition->bfexliquiditycharges(());
385 $insertposition->bfexseccharges(());
386 $insertposition->bfexnfacharges(());
387 $insertposition->bfexorigclients(());
388 $insertposition->bfexxchangerates(());
389 $insertposition->bfexendpoints(());
390 #$insertposition->bfexdates(());
391 #$insertposition->positiondate($posdate);
392
393 # Check to see which side to inject this in
394 if(IsBuySide($side)) {
395 DebugPrintOut("Inject previous day's buy: $timestamp $positionid $positionpx $origqty from $origclient $leavesqty $client $side $endpoint\n");
396 # Inject a buy
397 my @existingposarray;
398 if(exists $openlongpositionbyclientsymbol{$client} and defined $openlongpositionbyclientsymbol{$client}{$symbol}) {
399 @existingposarray = @{$openlongpositionbyclientsymbol{$client}{$symbol}};
400 }
401 else {
402 @existingposarray = ();
403 }
404 push(@existingposarray, $insertposition);
405 $openlongpositionbyclientsymbol{$client}{$symbol} = \@existingposarray;
406 }
407 else {
408 DebugPrintOut("Inject previous day's sell: $timestamp $positionid $positionpx $origqty from $origclient $leavesqty $client $side $endpoint\n");
409 # Inject a sell
410 my @existingposarray;
411 if(exists $openshortpositionbyclientsymbol{$client} and defined $openshortpositionbyclientsymbol{$client}{$symbol}) {
412 @existingposarray = @{$openshortpositionbyclientsymbol{$client}{$symbol}};
413 }
414 else {
415 @existingposarray = ();
416 }
417 push(@existingposarray, $insertposition);
418 $openshortpositionbyclientsymbol{$client}{$symbol} = \@existingposarray;
419 }
420}
421
422# Print initial positions
423my %initialclisympostotal = ();
424# Total up the positions
425foreach my $clientkey (keys %openlongpositionbyclientsymbol) {
426 my %symbolhash = %{$openlongpositionbyclientsymbol{$clientkey}};
427 foreach my $symbolkey (keys %symbolhash) {
428 my @longposarr = @{$openlongpositionbyclientsymbol{$clientkey}{$symbolkey}};
429 foreach my $currpos (@longposarr) {
430 my $currposleaves = $currpos->leavesqty;
431 if(exists $initialclisympostotal{$clientkey} and defined $initialclisympostotal{$clientkey}{$symbolkey}) {
432 my $existingtotal = $initialclisympostotal{$clientkey}{$symbolkey};
433 $existingtotal += $currposleaves;
434 $initialclisympostotal{$clientkey}{$symbolkey} = $existingtotal;
435 }
436 else {
437 my $existingtotal = 0;
438 $existingtotal += $currposleaves;
439 $initialclisympostotal{$clientkey}{$symbolkey} = $existingtotal;
440 }
441 }
442 }
443}
444foreach my $clientkey (keys %openshortpositionbyclientsymbol) {
445 my %symbolhash = %{$openshortpositionbyclientsymbol{$clientkey}};
446 foreach my $symbolkey (keys %symbolhash) {
447 my @shortposarr = @{$openshortpositionbyclientsymbol{$clientkey}{$symbolkey}};
448 foreach my $currpos (@shortposarr) {
449 my $currposleaves = $currpos->leavesqty;
450 if(exists $initialclisympostotal{$clientkey} and defined $initialclisympostotal{$clientkey}{$symbolkey}) {
451 my $existingtotal = $initialclisympostotal{$clientkey}{$symbolkey};
452 $existingtotal -= $currposleaves;
453 $initialclisympostotal{$clientkey}{$symbolkey} = $existingtotal;
454 }
455 else {
456 my $existingtotal = 0;
457 $existingtotal -= $currposleaves;
458 $initialclisympostotal{$clientkey}{$symbolkey} = $existingtotal;
459 }
460 }
461 }
462}
463PrintOut("==========================================\n");
464PrintOut("LOADED INITIAL POSITIONS\n");
465PrintOut("==========================================\n");
466# Do the actual printout
467foreach my $clientkey (sort keys %initialclisympostotal) {
468 my %symbolhash = %{$initialclisympostotal{$clientkey}};
469 foreach my $symbolkey (sort keys %symbolhash) {
470 my $clisymtotal = $initialclisympostotal{$clientkey}{$symbolkey};
471 if($clisymtotal != 0) {
472 PrintOut("$clientkey : $symbolkey : $clisymtotal\n");
473 }
474 }
475}
476PrintOutStd("Initial position reception completed!\n");
477PrintOut("==========================================\n");
478
479########################################################################
480# Define database variables
481my $dbuser = 'ro' ;
482my $dbpasswd = 'ro';
483my $dbserver = 'sv-chof-bfrp';
484my $dbname = 'Trading';
485
486# Establish connection to the database
487my $dbh=DBI->connect("DBI:Sybase:$dbserver",$dbuser,$dbpasswd) or die "Cant connect to DB!!\n";
488$dbh->do("use $dbname") or die "Cannot connect to $dbname on $dbserver!\n";
489
490PrintOut("==========================================\n");
491PrintOut("Connection to database server $dbserver has been established\n");
492
493########################################################################
494# Initialize fills file
495my $fillsfromdatabase = 0;
496my $fillsfilecheck = "/datlib/actualpnl/fills." . $todaysymd . ".out";
497if($testwritemode) {
498 $fillsfilecheck = "testfills." . $todaysymd . ".out";
499}
500open(FILLSFILE, "$fillsfilecheck") || print "No fills file detected at $fillsfilecheck! This run will write fills in!\n";
501FILLSFILE->autoflush;
502
503########################################################################
504# Go ahead and start pulling down data for the specified date, or a scan from pnlfills, depending on the runmode
505my $sth_str;
506my $xtra_str;
507my $xtra_proc;
508my $tid_tracker = 0;
509
510REALTIMELOOP:
511
512my $realtimemode = 0;
513if($runmode eq "FullDayCalc") {
514 # Pull data for transaction day
515 $sth_str= "SELECT client,account,symbol,side,endpoint,ymd,fillid,lastfillquantity,lastfillprice,closingprice,prodmultiplier,xchangerate,time,originalmessageid,primeclearcharge,globexclearcharge,globexexcharge,liquiditycredit,primeseccharge,nfacharge,tid FROM vw_pnlreports_3_ALLPNLUNFAIL_MOREVARS_LASTYEAR WHERE ymd='$todaysymd' ORDER BY tid ASC";
516}
517elsif($runmode eq "RealTime") {
518 GenerateMarksMap();
519 $realtimemode = 1;
520 $sth_str= "SELECT client,account,symbol,side,endpoint,ymd,fillid,lastfillquantity,lastfillprice,limitprice,prodmultiplier,snapxrate,time,originalmessageid,clearcharge,exchangecharge,liquiditycharge,seccharge,nfacharge,tid FROM pnlfills WHERE (tid > '$tid_tracker') ORDER BY tid ASC";
521}
522
523PrintOut("Original query for fill information:\n$sth_str\n");
524
525# QUERY replacement to mitigate an issue with FreeTDS and float / bigint operations on the table
526if ($sth_str =~ /SELECT\s+(.*)\s+FROM/i) { # match selected field string
527 my $field_str = $1;
528 my @fields = split ",", $field_str; # parse individual fields
529 map s/\s//g, @fields; # get rid of spaces
530 my $new_str = join ", ", (map {sprintf "convert(varchar(50), $_)"} @fields); # construct new query string
531 my d_field_str = quotemeta($field_str); # prepare regex replacement string
532 $xtra_str = $sth_str;
533 $xtra_str =~ s/$quoted_field_str/$new_str/i # actual replacement
534}
535
536PrintOut("Modified query for fill information:\n$xtra_str\n");
537
538if($runmode eq "RealTime") {
539 PrintOut("Looping with tid: $tid_tracker!\n");
540}
541
542# Extracted data should go here
543my $viewdata;
544
545PrintOutStd("Attempting to initialize / reclaim fill variables!\n");
546
547# Check to see if we have an existing fills file to reference.
548# This will make things much faster for loading / testing.
549if((-e $fillsfilecheck) and (!$opt_fillsfromdatabase) and (!$realtimemode)) {
550 PrintOutStd("Fills file detected! Retrieving today's fills from $fillsfilecheck\n");
551
552 # Override existing view data with fill injected views
553 @$viewdata = ();
554 while(<FILLSFILE>) {
555 my $currline = $_;
556 push(@$viewdata, $currline);
557 }
558
559 PrintOutStd("Fills retrieval completed!\n");
560}
561else {
562 if($realtimemode) {
563 PrintOutStd("Real time run mode detected! Retrieving today's fills from database!\n");
564 }
565 else {
566 PrintOutStd("No fills file detected! Retrieving today's fills from database!\n");
567 }
568
569 # Execute the query
570 $xtra_proc = $dbh->prepare($xtra_str);
571 $xtra_proc->execute;
572 $viewdata = $xtra_proc->fetchall_arrayref;
573
574 # Indicate that we're getting fills from the database
575 $fillsfromdatabase = 1;
576}
577
578# FILL TRACKING VARIABLES
579my $client;
580my $account;
581my $symbol;
582my $side;
583my $endpoint;
584my $fillid;
585my $lastfillquantity;
586my $lastfillprice;
587my $prodmultiplier;
588my $xchangerate;
589my $time;
590my $queryymd;
591my $origmsgid;
592my $clearcharge;
593my $exchangecharge;
594my $liquiditycharge;
595my $seccharge;
596my $nfacharge;
597my $tid;
598
599# Check to see which side this fill is on.
600# If it's not a buy, assume it's a sell
601my $contraposreference;
602my $sameposreference;
603my $contraintexreference;
604my $sameintexreference;
605my $sameside;
606my $contraside;
607
608# Start the aggregation process
609foreach my $row (@$viewdata) {
610 # Populate the fill variables
611 if($fillsfromdatabase) {
612 # From database --> Check to see if we're doing real time
613=details for queries
614 if($runmode eq "FullDayCalc") {
615 # Pull data for transaction day
616 $sth_str= "SELECT client,account,symbol,side,endpoint,ymd,fillid,lastfillquantity,lastfillprice,closingprice,prodmultiplier,xchangerate,time,originalmessageid,primeclearcharge,globexclearcharge,globexexcharge,liquiditycredit,primeseccharge,nfacharge,tid FROM vw_pnlreports_3_ALLPNLUNFAIL_MOREVARS_LASTYEAR WHERE ymd='$todaysymd' ORDER BY inserttime ASC";
617 }
618 elsif($runmode eq "RealTime") {
619 $realtimemode = 1;
620 $sth_str= "SELECT client,account,symbol,side,endpoint,ymd,fillid,lastfillquantity,lastfillprice,limitprice,prodmultiplier,snapxrate,time,originalmessageid,clearcharge,exchangecharge,liquiditycharge,seccharge,nfacharge,tid FROM pnlfills WHERE (tid > '$tid_tracker') ORDER BY inserttime ASC";
621 }
622=cut
623
624 if(!$realtimemode) {
625 # Historical pull, from vw_pnlreports_3_ALLPNLUNFAIL_MOREVARS_LASTYEAR
626 $client = $row->[0];
627 $account = $row->[1];
628 $symbol = $row->[2];
629 $side = $row->[3];
630 $endpoint= $row->[4];
631 $queryymd = $row->[5];
632 $fillid = $row->[6];
633 $lastfillquantity = $row->[7];
634 $lastfillprice = $row->[8];
635 $prodmultiplier = $row->[10];
636 $xchangerate = $row->[11];
637 $time = $row->[12];
638 $origmsgid = $row->[13];
639 $clearcharge = $row->[14];
640
641 # So, from pnl reports, we have two charges that comprise the "exchangecharge".
642 # Add them together to get the real result.
643 my $globexclearcharge = $row->[15];
644 my $globexexcharge = $row->[16];
645 $exchangecharge = $globexclearcharge + $globexexcharge;
646
647 $liquiditycharge = $row->[17];
648 $seccharge = $row->[18];
649 $nfacharge = $row->[19];
650 $tid = $row->[20];
651 }
652 else {
653 # Real time pull, from pnlfills
654 $client = $row->[0];
655 $account = $row->[1];
656 $symbol = $row->[2];
657 $side = $row->[3];
658 $endpoint= $row->[4];
659 $queryymd = $row->[5];
660 $fillid = $row->[6];
661 $lastfillquantity = $row->[7];
662 $lastfillprice = $row->[8];
663 $prodmultiplier = $row->[10];
664 $xchangerate = 1 / ($row->[11]);
665 $time = $row->[12];
666 $origmsgid = $row->[13];
667 $clearcharge = $row->[14];
668 $exchangecharge = $row->[15];
669 $liquiditycharge = $row->[16];
670 $seccharge = $row->[17];
671 $nfacharge = $row->[18];
672 $tid = $row->[19];
673 }
674 }
675 else {
676 # From fills file
677 my @splitvalues = split(',', $row);
678 $client = $splitvalues[0];
679 $account = $splitvalues[1];
680 $symbol = $splitvalues[2];
681 $side = $splitvalues[3];
682 $endpoint= $splitvalues[4];
683 $fillid = $splitvalues[5];
684 $lastfillquantity = $splitvalues[6];
685 $lastfillprice = $splitvalues[7];
686 $prodmultiplier = $splitvalues[8];
687 $xchangerate = $splitvalues[9];
688 $time = $splitvalues[10];
689 $queryymd = $splitvalues[11];
690 $origmsgid = $splitvalues[12];
691 $clearcharge = $splitvalues[13];
692 $exchangecharge = $splitvalues[14];
693 $liquiditycharge = $splitvalues[15];
694 $seccharge = $splitvalues[16];
695 $nfacharge = $splitvalues[17];
696 $tid = $splitvalues[18];
697 $tid =~ s/^\s+|\s+$//g;
698 }
699
700 # Update the tid tracker for the next iteration
701 $tid_tracker = $tid;
702
703 # For later fills injection
704 push(@fillwritestrings,"$client,$account,$symbol,$side,$endpoint,$fillid,$lastfillquantity,$lastfillprice,$prodmultiplier,$xchangerate,$time,$queryymd,$origmsgid,$clearcharge,$exchangecharge,$liquiditycharge,$seccharge,$nfacharge,$tid");
705
706 # Check the existing ID to see if we should ignore it.
707 if(ShouldIgnoreID($fillid)) {
708 PrintOutStd("Ledger ignore is in place for ID ($fillid)! Moving on to next fill!\n");
709 next;
710 }
711
712 # Override the quantity if we have a ledger transaction
713 my $idinmap = IsIdInQtyModMap($fillid);
714 if($idinmap) {
715 my $qtyfrommap = $ledgerqtymodactions{$fillid};
716 PrintOutStd("Ledger size override detected! Changing fillquantity from $lastfillquantity to $qtyfrommap for ID: $fillid!\n");
717 $lastfillquantity = $qtyfrommap;
718 }
719
720 # Start the fill processing
721 PrintOut("==========================================\n");
722 PrintOut("FILL: $time: $client:$symbol:$endpoint $side $lastfillquantity @ $lastfillprice --> $fillid --> $origmsgid\n");
723
724 $contraposreference = (($side =~ "B") ? \%openshortpositionbyclientsymbol : \%openlongpositionbyclientsymbol);
725 $sameposreference = (($side =~ "B") ? \%openlongpositionbyclientsymbol : \%openshortpositionbyclientsymbol);
726 $contraintexreference = (($side =~ "B") ? \%openshortintexbysymbol : \%openlongintexbysymbol);
727 $sameintexreference = (($side =~ "B") ? \%openlongintexbysymbol : \%openshortintexbysymbol);
728 $sameside = (($side =~ "B") ? "B" : "S");
729 $contraside = (($side =~ "B") ? "S" : "B");
730
731 #=====================================================================================================================================
732 # START CHECKING FOR BFEX
733 #=====================================================================================================================================
734
735 # First, check to see if we're dealing with a BFEX transaction
736 if(IsInternalCrossEndpoint($endpoint)) {
737 DebugPrintOut("BFEX detected! Initiating necessary action\n");
738
739 # Check to see if we have no opposing BFEX's on the other side
740 my $contradefined;
741 my @contraintexarray;
742 my $contraintexsize = 0;
743 if(defined $$contraintexreference{$symbol}) {
744 $contradefined = 1;
745 @contraintexarray = @{$$contraintexreference{$symbol}};
746 $contraintexsize = @contraintexarray;
747 }
748
749 # If we're dealing with a BFEX, check to see if we have any contra BFEXs
750 if($contradefined and ($contraintexsize > 0)) {
751 my $contraintexfound;
752 my $contracounter = 0;
753 # If we do, look for the opposing transaction to this BFEX. If it can't be found, exit out with an error.
754 foreach my $contraintexpos (@contraintexarray) {
755 my $contraintexsize = $contraintexpos->origqty;
756 my $contraintexprice = $contraintexpos->positionpx;
757 my $contraintexclient = $contraintexpos->origclient;
758 if(($contraintexsize == $lastfillquantity) && ($contraintexprice == $lastfillprice)) {
759 # We've found the contra transaction.
760 # Start breaking it down and assigning proper prices / position
761 # to the new client.
762 my @origqtys = @{$contraintexpos->bfexorigqtys};
763 my @sizes = @{$contraintexpos->bfexsizes};
764 my @prices = @{$contraintexpos->bfexprices};
765 my @posids = @{$contraintexpos->bfexposids};
766 my @origids = @{$contraintexpos->bfexorigids};
767 my @clearcharges = @{$contraintexpos->bfexclearcharges};
768 my @exchangecharges = @{$contraintexpos->bfexexchangecharges};
769 my @liquiditycharges = @{$contraintexpos->bfexliquiditycharges};
770 my @seccharges = @{$contraintexpos->bfexseccharges};
771 my @nfacharges = @{$contraintexpos->bfexnfacharges};
772 my @origclients = @{$contraintexpos->bfexorigclients};
773 my @xchangerates = @{$contraintexpos->bfexxchangerates};
774 my @endpoints = @{$contraintexpos->bfexendpoints};
775 #my @dates = @{$contraintexpos->bfexdates};
776
777 # Perform the BFEX transfer, using the pre-allocated prices / sizes.
778 my $trackingexcounter = $lastfillquantity;
779 while($trackingexcounter > 0) {
780 my $sizessize = @sizes;
781 my $pricessize = @prices;
782 if($sizessize <= 0) {
783 PrintOut("WARNING: Ran out of contra sizes for BFEX draw! PROMPTing user for input!\n");
784 last;
785 }
786 if($pricessize <= 0) {
787 PrintOut("WARNING: Ran out of contra prices for BFEX draw?! PROMPTing user for input!\n");
788 last;
789 }
790
791 # Extract the variables that we need for a singular transaction
792 my $setposid = shift(@posids);
793 my $setorigid = shift(@origids);
794 my $setorigqty = shift(@origqtys);
795 my $setsize = shift(@sizes);
796 my $setprice = shift(@prices);
797 my $setclearcharge = shift(@clearcharges);
798 my $setexchangecharge = shift(@exchangecharges);
799 my $setliquiditycharge = shift(@liquiditycharges);
800 my $setseccharge = shift(@seccharges);
801 my $setnfacharge = shift(@nfacharges);
802 my $setorigclient = shift(@origclients);
803 my $setxchangerate = shift(@xchangerates);
804 my $setendpoint = shift(@endpoints);
805 #my $setdate = shift(@dates);
806
807 # Subtract from tracking prior to any operations
808 $trackingexcounter -= $setsize;
809
810 DebugPrintOut("Pulled portion of BFEX is for total size $setsize and total price $setprice!\n");
811
812 # Check to make sure we don't have any contra positions to eliminate as we're taking on this BFEX.
813 if(exists $$contraposreference{$client} and defined $$contraposreference{$client}{$symbol}) {
814 my @contraposarr = @{$$contraposreference{$client}{$symbol}};
815 my $contraposamt = @contraposarr;
816 while(($setsize > 0) && ($contraposamt > 0)) {
817 my $contraposition = shift(@contraposarr);
818 my $contraorigqty = $contraposition->origqty;
819 my $contraleaves = $contraposition->leavesqty;
820 my $contraorigclient = $contraposition->origclient;
821 my $contraprice = $contraposition->positionpx;
822 my $contratime = $contraposition->timestring;
823 my $contraendpoint = $contraposition->endpoint;
824 my $contraaccount = $contraposition->account;
825 my $contrapositionid = $contraposition->positionid;
826 my $contraorigid = $contraposition->origmsgid;
827 my $contraclearcharge = $contraposition->clearcharge;
828 my $contraexchangecharge = $contraposition->exchangecharge;
829 my $contraliquiditycharge = $contraposition->liquiditycharge;
830 my $contraseccharge = $contraposition->seccharge;
831 my $contranfacharge = $contraposition->nfacharge;
832 my $contraxchangerate = $contraposition->xchangerate;
833 my $amounttoclose = 0;
834 my $totalfeecharge = 0;
835 DebugPrintOut("Existing contra position of $contraleaves @ $contraprice is in place to counteract incoming BFEX size of $setsize\n");
836 if($contraleaves >= $setsize) {
837 # We have enough in this contra position to cover this incoming transfer.
838 $amounttoclose = $setsize;
839 $contraleaves -= $setsize;
840 if($contraleaves > 0) {
841 # If we still have anything left, put it back
842 $contraposition->leavesqty($contraleaves);
843 unshift(@contraposarr, $contraposition);
844 }
845
846 # We are taking on the full fee charge for the set, and a partial set for this contra quantity
847 my $feeratiomult = $amounttoclose / $contraorigqty;
848 $contraclearcharge = $contraclearcharge * $feeratiomult;
849 $contraexchangecharge = $contraexchangecharge * $feeratiomult;
850 $contraliquiditycharge = $contraliquiditycharge * $feeratiomult;
851 $contraseccharge = $contraseccharge * $feeratiomult;
852 $contranfacharge = $contranfacharge * $feeratiomult;
853 if(ShouldConvertFeeEndpoint($contraendpoint)) {
854 #$contraclearcharge = $contraclearcharge / $contraxchangerate;
855 $contraexchangecharge = $contraexchangecharge / $contraxchangerate;
856 $contraliquiditycharge = $contraliquiditycharge / $contraxchangerate;
857 $contraseccharge = $contraseccharge / $contraxchangerate;
858 $contranfacharge = $contranfacharge / $contraxchangerate;
859 }
860 my $totalcontracharge = $contraclearcharge + $contraexchangecharge + $contraliquiditycharge + $contraseccharge + $contranfacharge;
861
862 my $setfeeratiomult = $amounttoclose / $setorigqty;
863 my $setclearcopy = $setclearcharge * $setfeeratiomult;
864 my $setexchangecopy = $setexchangecharge * $setfeeratiomult;
865 my $setliquiditycopy = $setliquiditycharge * $setfeeratiomult;
866 my $setseccopy = $setseccharge * $setfeeratiomult;
867 my $setnfacopy = $setnfacharge * $setfeeratiomult;
868 if(ShouldConvertFeeEndpoint($setendpoint)) {
869 #$setclearcopy = $setclearcopy / $setxchangerate;
870 $setexchangecopy = $setexchangecopy / $setxchangerate;
871 $setliquiditycopy = $setliquiditycopy / $setxchangerate;
872 $setseccopy = $setseccopy / $setxchangerate;
873 $setnfacopy = $setnfacopy / $setxchangerate;
874 }
875 my $totalsetcharge = $setclearcopy + $setexchangecopy + $setliquiditycopy + $setseccopy + $setnfacopy;
876
877 # We should have fee accumulations at this point
878 if($realtimemode) {
879 # Insert fees on the day
880 my $totalclearcharge = $contraclearcharge + $setclearcopy;
881 my $totalexchangecharge = $contraexchangecharge + $setexchangecopy;
882 my $totalliquiditycharge = $contraliquiditycharge + $setliquiditycopy;
883 my $totalseccharge = $contraseccharge + $setseccopy;
884 my $totalnfacharge = $contranfacharge + $setnfacopy;
885
886 InsertAmountToCASEMap(\%caseclearfeepnl, $contraorigclient, $contraaccount, $symbol, $contraendpoint, $totalclearcharge);
887 InsertAmountToCASEMap(\%caseexfeepnl, $contraorigclient, $contraaccount, $symbol, $contraendpoint, $totalexchangecharge);
888 InsertAmountToCASEMap(\%caseliqfeepnl, $contraorigclient, $contraaccount, $symbol, $contraendpoint, $totalliquiditycharge);
889 InsertAmountToCASEMap(\%casesecfeepnl, $contraorigclient, $contraaccount, $symbol, $contraendpoint, $totalseccharge);
890 InsertAmountToCASEMap(\%casenfafeepnl, $contraorigclient, $contraaccount, $symbol, $contraendpoint, $totalnfacharge);
891 }
892
893 $totalfeecharge = $totalcontracharge + $totalsetcharge;
894
895 # Insert the fee into a map
896 InsertFeeForClientSymbol($totalfeecharge, $contraorigclient, $symbol);
897
898 DebugPrintOut("Total Fee Charge Ia is: $totalfeecharge, generated from first ratio of ($amounttoclose / $contraorigqty) for $totalcontracharge. Second ratio is ($amounttoclose / $setorigqty), for $totalsetcharge.\n");
899
900 # Put the result back
901 $$contraposreference{$client}{$symbol} = \@contraposarr;
902 }
903 else {
904 $amounttoclose = $contraleaves;
905 $$contraposreference{$client}{$symbol} = \@contraposarr;
906
907 my $feeratiomult = $amounttoclose / $contraorigqty;
908 $contraclearcharge = $contraclearcharge * $feeratiomult;
909 $contraexchangecharge = $contraexchangecharge * $feeratiomult;
910 $contraliquiditycharge = $contraliquiditycharge * $feeratiomult;
911 $contraseccharge = $contraseccharge * $feeratiomult;
912 $contranfacharge = $contranfacharge * $feeratiomult;
913 if(ShouldConvertFeeEndpoint($contraendpoint)) {
914 #$contraclearcharge = $contraclearcharge / $contraxchangerate;
915 $contraexchangecharge = $contraexchangecharge / $contraxchangerate;
916 $contraliquiditycharge = $contraliquiditycharge / $contraxchangerate;
917 $contraseccharge = $contraseccharge / $contraxchangerate;
918 $contranfacharge = $contranfacharge / $contraxchangerate;
919 }
920 my $totalcontracharge = $contraclearcharge + $contraexchangecharge + $contraliquiditycharge + $contraseccharge + $contranfacharge;
921
922 # We are taking on the full contra quantity, and only a part of this set
923 my $setfeeratiomult = $amounttoclose / $setorigqty;
924 my $setclearcopy = $setclearcharge * $setfeeratiomult;
925 my $setexchangecopy = $setexchangecharge * $setfeeratiomult;
926 my $setliquiditycopy = $setliquiditycharge * $setfeeratiomult;
927 my $setseccopy = $setseccharge * $setfeeratiomult;
928 my $setnfacopy = $setnfacharge * $setfeeratiomult;
929 if(ShouldConvertFeeEndpoint($setendpoint)) {
930 #$setclearcopy = $setclearcopy / $setxchangerate;
931 $setexchangecopy = $setexchangecopy / $setxchangerate;
932 $setliquiditycopy = $setliquiditycopy / $setxchangerate;
933 $setseccopy = $setseccopy / $setxchangerate;
934 $setnfacopy = $setnfacopy / $setxchangerate;
935 }
936 my $totalsetcharge = $setclearcopy + $setexchangecopy + $setliquiditycopy + $setseccopy + $setnfacopy;
937
938 if($realtimemode) {
939 # Insert fees on the day
940 my $totalclearcharge = $contraclearcharge + $setclearcopy;
941 my $totalexchangecharge = $contraexchangecharge + $setexchangecopy;
942 my $totalliquiditycharge = $contraliquiditycharge + $setliquiditycopy;
943 my $totalseccharge = $contraseccharge + $setseccopy;
944 my $totalnfacharge = $contranfacharge + $setnfacopy;
945 InsertAmountToCASEMap(\%caseclearfeepnl, $contraorigclient, $contraaccount, $symbol, $contraendpoint, $totalclearcharge);
946 InsertAmountToCASEMap(\%caseexfeepnl, $contraorigclient, $contraaccount, $symbol, $contraendpoint, $totalexchangecharge);
947 InsertAmountToCASEMap(\%caseliqfeepnl, $contraorigclient, $contraaccount, $symbol, $contraendpoint, $totalliquiditycharge);
948 InsertAmountToCASEMap(\%casesecfeepnl, $contraorigclient, $contraaccount, $symbol, $contraendpoint, $totalseccharge);
949 InsertAmountToCASEMap(\%casenfafeepnl, $contraorigclient, $contraaccount, $symbol, $contraendpoint, $totalnfacharge);
950 }
951
952 $totalfeecharge = $totalcontracharge + $totalsetcharge;
953
954 # Insert the fee into a map
955 InsertFeeForClientSymbol($totalfeecharge, $contraorigclient, $symbol);
956
957 DebugPrintOut("Total Fee Charge Ib is: $totalfeecharge, generated from first ratio of ($amounttoclose / $contraorigqty) for $totalcontracharge. Second ratio is ($amounttoclose / $setorigqty), for $totalsetcharge.\n");
958 }
959
960 # Reduce the set size by the amount that we are going to close for this transaction
961 $setsize -= $amounttoclose;
962 DebugPrintOut("Remaining BFEX size to insert from this portion is $setsize, after transacting $amounttoclose!\n");
963
964 # Calculate PNL and close the transaction. PNL should go into the original client for this injection.
965 my $closedpnl = $amounttoclose * ((\%openshortpositionbyclientsymbol == $contraposreference) ? ($contraprice - $setprice) : ($setprice - $contraprice)) * $prodmultiplier / $xchangerate + $totalfeecharge;
966
967 if($realtimemode) {
968 # Insert the day PNL
969 my $closedpnlwithoutfees = $closedpnl - $totalfeecharge;
970 InsertAmountToCASEMap(\%casedaypnl, $contraorigclient, $contraaccount, $symbol, $contraendpoint, $closedpnlwithoutfees);
971 }
972
973 # Inject the closed PNL into the map
974 if(exists $closedpnlbyclientsymbol{$contraorigclient} and defined $closedpnlbyclientsymbol{$contraorigclient}{$symbol}) {
975 my $existingpnl = $closedpnlbyclientsymbol{$contraorigclient}{$symbol};
976 $existingpnl = $existingpnl + $closedpnl;
977 $closedpnlbyclientsymbol{$contraorigclient}{$symbol} = $existingpnl;
978 }
979 else {
980 $closedpnlbyclientsymbol{$contraorigclient}{$symbol} = $closedpnl;
981 }
982 DebugPrintOut("Additional closed PNL generated by this transaction of amount $amounttoclose is $closedpnl for originating client $contraorigclient!\n");
983 #PrintOut("CONTRA: ($contraorigclient:$closedpnl) -- $contratime: $contraorigclient:$symbol:$contraendpoint $contraside $contraleaves @ $contraprice --> $contrapositionid --> $contraorigid\n");
984
985 my $storedpnlnumber = $closedpnlbyclientsymbol{$contraorigclient}{$symbol};
986 PrintOut("SCONTRA: P&L: ($contraorigclient:$symbol:$closedpnl:$storedpnlnumber) -- ($contraside/$side) $amounttoclose $symbol @ ($contraprice/$setprice) ($contraorigid/$setorigid) in client $client\n");
987
988 # Update the array size reference
989 $contraposamt = @contraposarr;
990 }
991 }
992
993 # If we have anything remaining after examining existing contra positions
994 if($setsize > 0) {
995 # Add this position onto the client with
996 # proper size and price distributions.
997 my $insertposition = new TradePosition;
998 $insertposition->positionid($setposid);
999 $insertposition->origmsgid($setorigid);
1000 #$insertposition->timestring($tminusoneymd . "-" . $time);
1001 $insertposition->timestring($time);
1002 $insertposition->positionpx($setprice);
1003 $insertposition->origqty($setorigqty);
1004 $insertposition->leavesqty($setsize);
1005 $insertposition->client($client);
1006 $insertposition->account($account);
1007 $insertposition->symbol($symbol);
1008 $insertposition->side($side);
1009 $insertposition->endpoint($setendpoint);
1010 $insertposition->prodmultiplier($prodmultiplier);
1011 $insertposition->xchangerate($xchangerate);
1012 $insertposition->origclient($setorigclient);
1013 $insertposition->clearcharge($setclearcharge);
1014 $insertposition->exchangecharge($setexchangecharge);
1015 $insertposition->liquiditycharge($setliquiditycharge);
1016 $insertposition->seccharge($setseccharge);
1017 $insertposition->nfacharge($setnfacharge);
1018 $insertposition->bfexorigqtys(());
1019 $insertposition->bfexsizes(());
1020 $insertposition->bfexprices(());
1021 $insertposition->bfexposids(());
1022 $insertposition->bfexorigids(());
1023 $insertposition->bfexclearcharges(());
1024 $insertposition->bfexexchangecharges(());
1025 $insertposition->bfexliquiditycharges(());
1026 $insertposition->bfexseccharges(());
1027 $insertposition->bfexnfacharges(());
1028 $insertposition->bfexorigclients(());
1029 $insertposition->bfexxchangerates(());
1030 $insertposition->bfexendpoints(());
1031 #$insertposition->bfexdates(());
1032 #$insertposition->positiondate($setdate);
1033
1034 #DebugPrintOut("Injecting compensatory BFEX of $side $setsize @ $setprice for client $contraintexclient into $client off original fill of $lastfillquantity!\n");
1035 PrintOut("TRANSFER: $setsize / $setorigqty @ $setprice $symbol for $setorigclient (via $contraintexclient) into $client --> $setorigid\n");
1036
1037 # Re-position the array
1038 my @posarray;
1039 if(exists $$sameposreference{$client} and defined $$sameposreference{$client}{$symbol}) {
1040 @posarray = @{$$sameposreference{$client}{$symbol}};
1041 }
1042 else {
1043 @posarray = ();
1044 }
1045
1046 # We've decided to push this into the back as opposed to the front of the queue
1047 #unshift(@posarray, $insertposition);
1048 push(@posarray, $insertposition);
1049 $$sameposreference{$client}{$symbol} = \@posarray;
1050
1051 # Check client new total position and contra position remaining (if we didn't transact through
1052 # the entire thing with this BFEX)
1053 if($debugmode) {
1054 my $checktotalpos = GetTotalPositionForClientSymbol($client, $symbol);
1055 DebugPrintOut("New total position for $client:$symbol is $checktotalpos\n");
1056
1057 # Check contra position size
1058 my @contraposref;
1059 if(exists $$contraposreference{$client} and defined $$contraposreference{$client}{$symbol}) {
1060 @contraposref = @{$$contraposreference{$client}{$symbol}};
1061 my $contraposrefsize = @contraposref;
1062 my $contraposrefqty = 0;
1063 foreach my $contraposrefitem (@contraposref) {
1064 my $contraleavesitem = $contraposrefitem->leavesqty;
1065 $contraposrefqty += $contraleavesitem;
1066 }
1067 DebugPrintOut("Contra positions remaining: $contraposrefsize with total size $contraposrefqty\n");
1068 }
1069 else {
1070 DebugPrintOut("Contra positions remaining: NONE with total size NONE\n");
1071 }
1072 }
1073 }
1074 else {
1075 # Check contra position size, in debug mode only
1076 if($debugmode) {
1077 my @contraposref;
1078 if(exists $$contraposreference{$client} and defined $$contraposreference{$client}{$symbol}) {
1079 @contraposref = @{$$contraposreference{$client}{$symbol}};
1080 my $contraposrefsize = @contraposref;
1081 my $contraposrefqty = 0;
1082 foreach my $contraposrefitem (@contraposref) {
1083 my $contraleavesitem = $contraposrefitem->leavesqty;
1084 $contraposrefqty += $contraleavesitem;
1085 }
1086 DebugPrintOut("Contra positions remaining: $contraposrefsize with total size $contraposrefqty\n");
1087 }
1088 else {
1089 DebugPrintOut("Contra positions remaining: NONE with total size NONE\n");
1090 }
1091 }
1092 }
1093 }
1094
1095 # Break the loop
1096 $contraintexfound = 1;
1097 last;
1098 }
1099
1100 # Mark our place in the array to splice
1101 $contracounter++;
1102 }
1103
1104 if(!$contraintexfound) {
1105 # We should have found the other side of this BFEX. What happened?!
1106 PrintOut("CRITICAL ERROR: COULD NOT FIND THE OTHER SIDE OF THIS BFEX TRANSACTION: $fillid?!\n");
1107 #die "CRITICAL ERROR: COULD NOT FIND THE OTHER SIDE OF THIS BFEX TRANSACTION: $fillid?!\n";
1108 ErrorAndShutdown("CRITICAL ERROR: COULD NOT FIND THE OTHER SIDE OF THIS BFEX TRANSACTION: $fillid?!\n");
1109
1110 }
1111 else {
1112 # If we have found the originating BFEX, move on the next fill.
1113 # We have found our contra intex transaction. Remove the
1114 # index from the array. Put the contraintexarray back where we found it.
1115 splice @contraintexarray, $contracounter, 1;
1116 $$contraintexreference{$symbol} = \@contraintexarray;
1117 }
1118 }
1119 # There are no opposing BFEXes. Assume this is the initiating BFEX.
1120 else {
1121 # We have no opposing BFEX's, go ahead and inject this one, split
1122 # with the right prices according to what we are transfering out of this client.
1123 # At this point, we should have enough size in the client to be
1124 # able to transfer this stuff out anyway. We are checking against the client's
1125 # contrapositionmap. The idea is to generate sizes and prices for re-assignment
1126 # for a BFEX according to what positions are already there.
1127 my @origqtysarray = ();
1128 my @sizesarray = ();
1129 my @pricesarray = ();
1130 my @posidsarray = ();
1131 my @origidsarray = ();
1132 my @bfexcleararray = ();
1133 my @bfexexarray = ();
1134 my @bfexliquidarray = ();
1135 my @bfexsecchargearray = ();
1136 my @bfexnfachargearray = ();
1137 my @origclientsarray = ();
1138 my @xchangeratesarray = ();
1139 my @endpointsarray = ();
1140 my @datesarray = ();
1141
1142 # Check to see if we have opposing positions to extract and assign to the BFEX.
1143 if(exists $$contraposreference{$client} and defined $$contraposreference{$client}{$symbol}) {
1144 my $trackingquantity = $lastfillquantity;
1145 my @contraposarray = @{$$contraposreference{$client}{$symbol}};
1146 my $contraarrsize = @contraposarray;
1147
1148 # Before we start manipulating positions on the contra-side, we have to account
1149 # for the fact that there might not be enough size there to compensate for the
1150 # total transfer out. This happened on 01/03 for a BFEX for EQ_LBnqSpreadArcaNsdq1
1151 # due to a possible trader error or misplaced EFP.
1152 my $totalcontraquantity = 0;
1153 foreach my $contraposition (@contraposarray) {
1154 my $contraleaves = $contraposition->leavesqty;
1155 $totalcontraquantity += $contraleaves;
1156 }
1157 if($totalcontraquantity < $trackingquantity) {
1158 # We don't have enough size in the contra array for compensate
1159 # for this BFEX. Get position for diagnostic information.
1160 my $clientpositionrep = GetTotalPositionForClientSymbol($client, $symbol);
1161 PrintOutStd("WARNING: $client DOES NOT HAVE ENOUGH CONTRA SIZE TO ACCOUNT FOR BFEX SIZE OF $side $trackingquantity $symbol in ID $fillid! Current contra size is: $totalcontraquantity. Position for client is $clientpositionrep! PROMPTing user for input!\n");
1162 PromptForUserAction($fillid);
1163
1164 # Check the existing ID to see if we should ignore it.
1165 if(ShouldIgnoreID($fillid)) {
1166 PrintOutStd("Ledger ignore is in place for ID ($fillid)! Moving on to next fill!\n");
1167 next;
1168 }
1169
1170 # Scan to see if we have a quantity mod in place after prompting the user
1171 my $idinmap = IsIdInQtyModMap($fillid);
1172 if($idinmap) {
1173 # Modify leaves for this order to what is in the map
1174 my $qtyfrommap = $ledgerqtymodactions{$fillid};
1175 PrintOutStd("Ledger size override detected! Changing fillquantity from $lastfillquantity to $qtyfrommap for ID: $fillid!\n");
1176 $lastfillquantity = $qtyfrommap;
1177 $trackingquantity = $qtyfrommap;
1178 }
1179 }
1180
1181 # Iterate over the contraposreferencearray, and remove positions up to the size that
1182 # we need to accommodate. If there isn't enough size, prompt the user for input.
1183 if($contraarrsize > 0) {
1184 DebugPrintOut("Pulling out transactions to compensate for BFEX position. Number of transactions on $client for $symbol is $contraarrsize\n");
1185 while($trackingquantity > 0) {
1186 my $contraposition = shift(@contraposarray);
1187 my $contraorigqty = $contraposition->origqty;
1188 my $contraleaves= $contraposition->leavesqty;
1189 my $contraprice = $contraposition->positionpx;
1190 my $contraposid = $contraposition->positionid;
1191 my $contraorigid = $contraposition->origmsgid;
1192 my $contraclearcharge = $contraposition->clearcharge;
1193 my $contraexchangecharge = $contraposition->exchangecharge;
1194 my $contraliquiditycharge = $contraposition->liquiditycharge;
1195 my $contraseccharge = $contraposition->seccharge;
1196 my $contranfacharge = $contraposition->nfacharge;
1197 my $contraorigclient = $contraposition->origclient;
1198 my $contraxchangerate = $contraposition->xchangerate;
1199 my $contraendpoint = $contraposition->endpoint;
1200 #my $contradate = $contraposition->positiondate;
1201 if($contraleaves >= $trackingquantity) {
1202 # We still have remaining quantity to cover, and this single position
1203 # that is pulled off is enough to compensate for that quantity.
1204 my $amountremaining = $contraleaves - $trackingquantity;
1205 DebugPrintOut("Pushing $amountremaining @ $contraprice into size array for $contraorigclient in $client\n");
1206
1207 # So this is a fun little annoyance. If we're splitting a position
1208 # in this instance, we have to calculate the proportional fees.
1209 # Multiply each fee by the amount we're splitting off from the original
1210 # quantity, as the charge should be associated with the whole order.
1211 my $feeratiomultiplier = $trackingquantity / $contraorigqty;
1212 $contraclearcharge = $contraclearcharge * $feeratiomultiplier;
1213 $contraexchangecharge = $contraexchangecharge * $feeratiomultiplier;
1214 $contraliquiditycharge = $contraliquiditycharge * $feeratiomultiplier;
1215 $contraseccharge = $contraseccharge * $feeratiomultiplier;
1216 $contranfacharge = $contranfacharge * $feeratiomultiplier;
1217
1218 # Push it into the array
1219 push(@origqtysarray, $contraorigqty);
1220 push(@sizesarray, $trackingquantity);
1221 push(@pricesarray, $contraprice);
1222 push(@posidsarray, $contraposid);
1223 push(@origidsarray, $contraorigid);
1224 push(@bfexcleararray, $contraclearcharge);
1225 push(@bfexexarray, $contraexchangecharge);
1226 push(@bfexliquidarray, $contraliquiditycharge);
1227 push(@bfexsecchargearray, $contraseccharge);
1228 push(@bfexnfachargearray, $contranfacharge);
1229 push(@origclientsarray, $contraorigclient);
1230 push(@xchangeratesarray, $contraxchangerate);
1231 push(@endpointsarray, $contraendpoint);
1232 #push(@datesarray, $contradate);
1233
1234 # Don't put it in if we don't have any amount remaining
1235 if($amountremaining > 0) {
1236 $contraposition->leavesqty($amountremaining);
1237 unshift(@contraposarray, $contraposition);
1238 }
1239
1240 # Reset trackingquantity
1241 $trackingquantity = 0;
1242 }
1243 else {
1244 # We don't have enough off of this position to cover
1245 DebugPrintOut("Pushing $contraleaves @ $contraprice into size array for $contraorigclient in $client\n");
1246
1247 # Do the same fee ratio multiplier as above
1248 my $feeratiomultiplier = $contraleaves / $contraorigqty;
1249 $contraclearcharge = $contraclearcharge * $feeratiomultiplier;
1250 $contraexchangecharge = $contraexchangecharge * $feeratiomultiplier;
1251 $contraliquiditycharge = $contraliquiditycharge * $feeratiomultiplier;
1252 $contraseccharge = $contraseccharge * $feeratiomultiplier;
1253 $contranfacharge = $contranfacharge * $feeratiomultiplier;
1254
1255 # Push it into the array
1256 push(@origqtysarray, $contraorigqty);
1257 push(@sizesarray, $contraleaves);
1258 push(@pricesarray, $contraprice);
1259 push(@posidsarray, $contraposid);
1260 push(@origidsarray, $contraorigid);
1261 push(@bfexcleararray, $contraclearcharge);
1262 push(@bfexexarray, $contraexchangecharge);
1263 push(@bfexliquidarray, $contraliquiditycharge);
1264 push(@bfexsecchargearray, $contraseccharge);
1265 push(@bfexnfachargearray, $contranfacharge);
1266 push(@origclientsarray, $contraorigclient);
1267 push(@xchangeratesarray, $contraxchangerate);
1268 push(@endpointsarray, $contraendpoint);
1269 #push(@datesarray, $contradate);
1270 $trackingquantity -= $contraleaves;
1271
1272 if($trackingquantity > 0) {
1273 # Check to see if we have any remaining contras to
1274 # go against. If not, we are extracting size that is not actually there.
1275 $contraarrsize = @contraposarray;
1276 if($contraarrsize <= 0) {
1277 PrintOutStd("WARNING: No more contra positions to transfer for BFEX $fillid ($side $lastfillquantity $symbol @ $lastfillprice for $client). We've put in what's there. PROMPTing user for input!\n");
1278
1279 # Check the existing ID to see if we should ignore it.
1280 # Don't check for quantity override in this case.
1281 if(ShouldIgnoreID($fillid)) {
1282 PrintOutStd("Ledger ignore is in place for ID ($fillid)! Moving on to next fill!\n");
1283 next;
1284 }
1285
1286 # Unset the loop
1287 $trackingquantity = 0;
1288
1289 # Exit the loop
1290 last;
1291 }
1292 }
1293 }
1294 }
1295 }
1296 # If we don't have any contra positions, prompt the user.
1297 else {
1298 # We have no available contra positions even though the array is defined
1299 PrintOutStd("WARNING: No contra positions detected when trying to transact out a BFEX for $fillid. PROMPTing user for input!\n");
1300 PromptForUserAction($fillid);
1301
1302 # Check the existing ID to see if we should ignore it.
1303 if(ShouldIgnoreID($fillid)) {
1304 PrintOutStd("Ledger ignore is in place for ID ($fillid)! Moving on to next fill!\n");
1305 next;
1306 }
1307
1308 # Scan to see if we have a quantity mod in place after prompting the user
1309 my $idinmap = IsIdInQtyModMap($fillid);
1310 if($idinmap) {
1311 # Modify leaves for this order to what is in the map
1312 my $qtyfrommap = $ledgerqtymodactions{$fillid};
1313 PrintOutStd("Ledger size override detected! Changing fillquantity from $lastfillquantity to $qtyfrommap for ID: $fillid!\n");
1314 $lastfillquantity = $qtyfrommap;
1315 }
1316
1317 # Fake availability still for the BFEX generated position.
1318 # Because we're not sure of this position's origin, assume zero fees.
1319 push(@origqtysarray, $lastfillquantity);
1320 push(@sizesarray, $lastfillquantity);
1321 push(@pricesarray, $lastfillprice);
1322 push(@posidsarray, "?");
1323 push(@origidsarray, "?");
1324 push(@bfexcleararray, 0);
1325 push(@bfexexarray, 0);
1326 push(@bfexliquidarray, 0);
1327 push(@bfexsecchargearray, 0);
1328 push(@bfexnfachargearray, 0);
1329 push(@origclientsarray, $client);
1330 push(@xchangeratesarray, $xchangerate);
1331 push(@endpointsarray, $endpoint);
1332 #push(@datesarray, $todaysymd);
1333 }
1334
1335 # Put the array back for contra positions
1336 # after we have removed what we need to for the BFEX
1337 $$contraposreference{$client}{$symbol} = \@contraposarray;
1338 }
1339 # We don't have any positions available to extract and assign to the BFEX. Prompt the user for details.
1340 else {
1341 PrintOutStd("WARNING: Initiating BFEX found, but we have no contra positions to extract for prices / sizes for $client:$symbol fill ID: $fillid ($side $lastfillquantity @ $lastfillprice)! PROMPTing user for input!\n");
1342 PromptForUserAction($fillid);
1343
1344 # Take post-check actions
1345 # Check the existing ID to see if we should ignore it.
1346 if(ShouldIgnoreID($fillid)) {
1347 PrintOutStd("Ledger ignore is in place for ID ($fillid)! Moving on to next fill!\n");
1348 next;
1349 }
1350
1351 # Scan to see if we have a quantity mod in place after prompting the user
1352 my $idinmap = IsIdInQtyModMap($fillid);
1353 if($idinmap) {
1354 # Modify leaves for this order to what is in the map
1355 my $qtyfrommap = $ledgerqtymodactions{$fillid};
1356 PrintOutStd("Ledger size override detected! Changing fillquantity from $lastfillquantity to $qtyfrommap for ID: $fillid!\n");
1357 $lastfillquantity = $qtyfrommap;
1358 }
1359
1360 # Fake availability still for the BFEX generated position.
1361 push(@origqtysarray, $lastfillquantity);
1362 push(@sizesarray, $lastfillquantity);
1363 push(@pricesarray, $lastfillprice);
1364 push(@posidsarray, "?");
1365 push(@origidsarray, "?");
1366 push(@bfexcleararray, 0);
1367 push(@bfexexarray, 0);
1368 push(@bfexliquidarray, 0);
1369 push(@bfexsecchargearray, 0);
1370 push(@bfexnfachargearray, 0);
1371 push(@origclientsarray, $client);
1372 push(@xchangeratesarray, $xchangerate);
1373 push(@endpointsarray, $endpoint);
1374 #push(@datesarray, $todaysymd);
1375 }
1376
1377 # Generate the new BFEX position that will eventually
1378 # be transacted against
1379 my $insertposition = new TradePosition;
1380 $insertposition->positionid($fillid);
1381 $insertposition->origmsgid($origmsgid);
1382 #$insertposition->timestring($tminusoneymd . "-" . $time);
1383 $insertposition->timestring($time);
1384 $insertposition->positionpx($lastfillprice);
1385 $insertposition->origqty($lastfillquantity);
1386 $insertposition->leavesqty($lastfillquantity);
1387 $insertposition->client($client);
1388 $insertposition->account($account);
1389 $insertposition->symbol($symbol);
1390 $insertposition->side($side);
1391 $insertposition->endpoint($endpoint);
1392 $insertposition->prodmultiplier($prodmultiplier);
1393 $insertposition->xchangerate($xchangerate);
1394 $insertposition->origclient($client);
1395 $insertposition->clearcharge($clearcharge);
1396 $insertposition->exchangecharge($exchangecharge);
1397 $insertposition->liquiditycharge($liquiditycharge);
1398 $insertposition->seccharge($seccharge);
1399 $insertposition->nfacharge($nfacharge);
1400 $insertposition->bfexorigqtys(\@origqtysarray);
1401 $insertposition->bfexsizes(\@sizesarray);
1402 $insertposition->bfexprices(\@pricesarray);
1403 $insertposition->bfexposids(\@posidsarray);
1404 $insertposition->bfexorigids(\@origidsarray);
1405 $insertposition->bfexclearcharges(\@bfexcleararray);
1406 $insertposition->bfexexchangecharges(\@bfexexarray);
1407 $insertposition->bfexliquiditycharges(\@bfexliquidarray);
1408 $insertposition->bfexseccharges(\@bfexsecchargearray);
1409 $insertposition->bfexnfacharges(\@bfexnfachargearray);
1410 $insertposition->bfexorigclients(\@origclientsarray);
1411 $insertposition->bfexxchangerates(\@xchangeratesarray);
1412 $insertposition->bfexendpoints(\@endpointsarray);
1413 #$insertposition->bfexdates(\@datesarray);
1414 #$insertposition->positiondate($todaysymd);
1415
1416 # Info
1417 DebugPrintOut("Injecting ready BFEX for transfer into array: $side $lastfillquantity $symbol\n");
1418
1419 # Push into the array
1420 my @sameintexarray;
1421 if(defined $$sameintexreference{$symbol}) {
1422 @sameintexarray = @{$$sameintexreference{$symbol}};
1423 }
1424 else {
1425 @sameintexarray = ();
1426 }
1427 push(@sameintexarray, $insertposition);
1428 $$sameintexreference{$symbol} = \@sameintexarray;
1429 }
1430
1431 # If we have a BFEX, period, move on the next fill.
1432 next;
1433 }
1434
1435 #=====================================================================================================================================
1436 # END CHECKING FOR BFEX
1437 #=====================================================================================================================================
1438
1439 #=====================================================================================================================================
1440 # START CHECKING FOR CONTRA FILL
1441 #=====================================================================================================================================
1442
1443 # If we don't have a BFEX transaction, check to see if we have any contra positions to close out, and generate PNL.
1444 if(exists $$contraposreference{$client} and defined $$contraposreference{$client}{$symbol}) {
1445 DebugPrintOut("Contra position array found! Iterating through position array!\n");
1446
1447 # Preserve the original quantity in case we need it later
1448 my $originalquantity = $lastfillquantity;
1449
1450 # Iterate through the contra positions until there are none left, or until this position has been closed. At that point, put any remaining position into the open positions for this client on this same side.
1451 while($lastfillquantity > 0) {
1452 DebugPrintOut("Iterating with lastfillquantity of $lastfillquantity\n");
1453 my (@positionarray, @pricearray);
1454
1455 # Check to make sure we have positions left on the position array
1456 # This is inefficient, constantly re-referencing the hash. I will have to fix this later.
1457 @positionarray = @{$$contraposreference{$client}{$symbol}};
1458 my $possize = @positionarray;
1459
1460 if($possize > 0) {
1461 DebugPrintOut("$possize elements detected in contra position array!\n");
1462
1463 # Examine first element of the position array
1464 my $contraposobject = shift(@positionarray);
1465 my $contratime = $contraposobject->timestring;
1466 my $contraorigqty = $contraposobject->origqty;
1467 my $contrafifoposition = $contraposobject->leavesqty;
1468 my $contrafifoprice = $contraposobject->positionpx;
1469 my $clientforpnl = $contraposobject->origclient;
1470 my $contrapositionid = $contraposobject->positionid;
1471 my $contraaccount = $contraposobject->account;
1472 my $idforpnl = $contraposobject->origmsgid;
1473 my $contraendpoint = $contraposobject->endpoint;
1474 my $contraclearcharge = $contraposobject->clearcharge;
1475 my $contraexchangecharge = $contraposobject->exchangecharge;
1476 my $contraliquiditycharge = $contraposobject->liquiditycharge;
1477 my $contraseccharge = $contraposobject->seccharge;
1478 my $contranfacharge = $contraposobject->nfacharge;
1479 my $contraxchangerate = $contraposobject->xchangerate;
1480
1481 DebugPrintOut("FIFO pull: ($idforpnl) ==> $contrafifoposition @ $contrafifoprice\n");
1482
1483 my $shouldexitloop = 0;
1484 my $totalfeecharge = 0;
1485 if($contrafifoposition >= $lastfillquantity) {
1486 # Our contra position outweighs this current fill.
1487 # Assign a closed pnl and unshift the remnant of the position,
1488 # as well as the price.
1489 $contraposobject->leavesqty($contrafifoposition - $lastfillquantity);
1490
1491 # Replace this position as long as the filled position isn't equal
1492 if($contrafifoposition != $lastfillquantity) {
1493 unshift(@positionarray, $contraposobject);
1494 }
1495
1496 # Reassign the position and price arrays
1497 $$contraposreference{$client}{$symbol} = \@positionarray;
1498
1499 # Exit the loop
1500 $shouldexitloop = 1;
1501
1502 # Proportion the fees accordingly
1503 my $feeratiomult = $lastfillquantity / $contraorigqty;
1504 $contraclearcharge = $contraclearcharge * $feeratiomult;
1505 $contraexchangecharge = $contraexchangecharge * $feeratiomult;
1506 $contraliquiditycharge = $contraliquiditycharge * $feeratiomult;
1507 $contraseccharge = $contraseccharge * $feeratiomult;
1508 $contranfacharge = $contranfacharge * $feeratiomult;
1509 if(ShouldConvertFeeEndpoint($contraendpoint)) {
1510 #$contraclearcharge = $contraclearcharge / $contraxchangerate;
1511 $contraexchangecharge = $contraexchangecharge / $contraxchangerate;
1512 $contraliquiditycharge = $contraliquiditycharge / $contraxchangerate;
1513 $contraseccharge = $contraseccharge / $contraxchangerate;
1514 $contranfacharge = $contranfacharge / $contraxchangerate;
1515 }
1516 my $totalcontracharge = $contraclearcharge + $contraexchangecharge + $contraliquiditycharge + $contraseccharge + $contranfacharge;
1517
1518 my $setfeeratiomult = $lastfillquantity / $originalquantity;
1519 my $setclearcharge = $clearcharge * $setfeeratiomult;
1520 my $setexchangecharge = $exchangecharge * $setfeeratiomult;
1521 my $setliquiditycharge = $liquiditycharge * $setfeeratiomult;
1522 my $setseccharge = $seccharge * $setfeeratiomult;
1523 my $setnfacharge = $nfacharge * $setfeeratiomult;
1524 if(ShouldConvertFeeEndpoint($endpoint)) {
1525 #$setclearcharge = $setclearcharge / $xchangerate;
1526 $setexchangecharge = $setexchangecharge / $xchangerate;
1527 $setliquiditycharge = $setliquiditycharge / $xchangerate;
1528 $setseccharge = $setseccharge / $xchangerate;
1529 $setnfacharge = $setnfacharge / $xchangerate;
1530 }
1531 my $totalsetcharge = $setclearcharge + $setexchangecharge + $setliquiditycharge + $setseccharge + $setnfacharge;
1532
1533 # Accumulate the total fee
1534 $totalfeecharge = $totalcontracharge + $totalsetcharge;
1535
1536 if($realtimemode) {
1537 # Insert fees on the day
1538 my $totalclearcharge = $contraclearcharge + $setclearcharge;
1539 my $totalexchangecharge = $contraexchangecharge + $setexchangecharge;
1540 my $totalliquiditycharge = $contraliquiditycharge + $setliquiditycharge;
1541 my $totalseccharge = $contraseccharge + $setseccharge;
1542 my $totalnfacharge = $contranfacharge + $setnfacharge;
1543 InsertAmountToCASEMap(\%caseclearfeepnl, $clientforpnl, $contraaccount, $symbol, $contraendpoint, $totalclearcharge);
1544 InsertAmountToCASEMap(\%caseexfeepnl, $clientforpnl, $contraaccount, $symbol, $contraendpoint, $totalexchangecharge);
1545 InsertAmountToCASEMap(\%caseliqfeepnl, $clientforpnl, $contraaccount, $symbol, $contraendpoint, $totalliquiditycharge);
1546 InsertAmountToCASEMap(\%casesecfeepnl, $clientforpnl, $contraaccount, $symbol, $contraendpoint, $totalseccharge);
1547 InsertAmountToCASEMap(\%casenfafeepnl, $clientforpnl, $contraaccount, $symbol, $contraendpoint, $totalnfacharge);
1548 }
1549
1550 # Insert the fee into a map
1551 InsertFeeForClientSymbol($totalfeecharge, $clientforpnl, $symbol);
1552
1553 # Debug print out
1554 DebugPrintOut("Total Fee Charge IIa is: $totalfeecharge, generated from first ratio of ($lastfillquantity / $contraorigqty) for $totalcontracharge. Second ratio is ($lastfillquantity / $originalquantity), for $totalsetcharge.\n");
1555 }
1556 else {
1557 # Reassign the position and price arrays - now without this position,
1558 # as it has been "filled"
1559 $$contraposreference{$client}{$symbol} = \@positionarray;
1560
1561 # Proportion the fees accordingly
1562 my $feeratiomult = $contrafifoposition / $contraorigqty;
1563 $contraclearcharge = $contraclearcharge * $feeratiomult;
1564 $contraexchangecharge = $contraexchangecharge * $feeratiomult;
1565 $contraliquiditycharge = $contraliquiditycharge * $feeratiomult;
1566 $contraseccharge = $contraseccharge * $feeratiomult;
1567 $contranfacharge = $contranfacharge * $feeratiomult;
1568 if(ShouldConvertFeeEndpoint($contraendpoint)) {
1569 #$contraclearcharge = $contraclearcharge / $contraxchangerate;
1570 $contraexchangecharge = $contraexchangecharge / $contraxchangerate;
1571 $contraliquiditycharge = $contraliquiditycharge / $contraxchangerate;
1572 $contraseccharge = $contraseccharge / $contraxchangerate;
1573 $contranfacharge = $contranfacharge / $contraxchangerate;
1574 }
1575 my $totalcontracharge = $contraclearcharge + $contraexchangecharge + $contraliquiditycharge + $contraseccharge + $contranfacharge;
1576
1577 my $setfeeratiomult = $contrafifoposition / $originalquantity;
1578 my $setclearcharge = $clearcharge * $setfeeratiomult;
1579 my $setexchangecharge = $exchangecharge * $setfeeratiomult;
1580 my $setliquiditycharge = $liquiditycharge * $setfeeratiomult;
1581 my $setseccharge = $seccharge * $setfeeratiomult;
1582 my $setnfacharge = $nfacharge * $setfeeratiomult;
1583 if(ShouldConvertFeeEndpoint($endpoint)) {
1584 #$setclearcharge = $setclearcharge / $xchangerate;
1585 $setexchangecharge = $setexchangecharge / $xchangerate;
1586 $setliquiditycharge = $setliquiditycharge / $xchangerate;
1587 $setseccharge = $setseccharge / $xchangerate;
1588 $setnfacharge = $setnfacharge / $xchangerate;
1589 }
1590 my $totalsetcharge = $setclearcharge + $setexchangecharge + $setliquiditycharge + $setseccharge + $setnfacharge;
1591
1592 $totalfeecharge = $totalcontracharge + $totalsetcharge;
1593
1594 if($realtimemode) {
1595 # Insert fees on the day
1596 my $totalclearcharge = $contraclearcharge + $setclearcharge;
1597 my $totalexchangecharge = $contraexchangecharge + $setexchangecharge;
1598 my $totalliquiditycharge = $contraliquiditycharge + $setliquiditycharge;
1599 my $totalseccharge = $contraseccharge + $setseccharge;
1600 my $totalnfacharge = $contranfacharge + $setnfacharge;
1601 InsertAmountToCASEMap(\%caseclearfeepnl, $clientforpnl, $contraaccount, $symbol, $contraendpoint, $totalclearcharge);
1602 InsertAmountToCASEMap(\%caseexfeepnl, $clientforpnl, $contraaccount, $symbol, $contraendpoint, $totalexchangecharge);
1603 InsertAmountToCASEMap(\%caseliqfeepnl, $clientforpnl, $contraaccount, $symbol, $contraendpoint, $totalliquiditycharge);
1604 InsertAmountToCASEMap(\%casesecfeepnl, $clientforpnl, $contraaccount, $symbol, $contraendpoint, $totalseccharge);
1605 InsertAmountToCASEMap(\%casenfafeepnl, $clientforpnl, $contraaccount, $symbol, $contraendpoint, $totalnfacharge);
1606 }
1607
1608 # Insert the fee into a map
1609 InsertFeeForClientSymbol($totalfeecharge, $clientforpnl, $symbol);
1610
1611 # Debug print out
1612 DebugPrintOut("Total Fee Charge IIb is: $totalfeecharge, generated from first ratio of ($lastfillquantity / $contraorigqty) for $totalcontracharge. Second ratio is ($lastfillquantity / $originalquantity), for $totalsetcharge.\n");
1613 }
1614
1615 # Internal cross check
1616 my $fifoendpoint = $contraposobject->endpoint;
1617
1618 # Calculate out closed pnl
1619 my $minqty = min $contrafifoposition, $lastfillquantity;
1620 my $closedpnl = $minqty * ((\%openshortpositionbyclientsymbol == $contraposreference) ? ($contrafifoprice - $lastfillprice) : ($lastfillprice - $contrafifoprice)) * $prodmultiplier / $xchangerate + $totalfeecharge;
1621 DebugPrintOut("Closed pnl variables: Incoming fill: $side $lastfillquantity\@$lastfillprice Contra position / px: $contrafifoposition\@$contrafifoprice\n");
1622 DebugPrintOut("Closed pnl for this transaction is: $closedpnl\n");
1623
1624 # Insert the closed pnl into a map
1625 # Get original client position pnl
1626 if($clientforpnl ne $client) {
1627 DebugPrintOut("Re-directing PNL from $client to $clientforpnl due to internal transfer!\n");
1628 }
1629
1630 if($realtimemode) {
1631 # Insert fees on the day
1632 my $closedpnlwithoutfees = $closedpnl - $totalfeecharge;
1633 InsertAmountToCASEMap(\%casedaypnl, $clientforpnl, $contraaccount, $symbol, $contraendpoint, $closedpnlwithoutfees);
1634 }
1635
1636 # Assign closed pnl
1637 if(exists $closedpnlbyclientsymbol{$clientforpnl} and defined $closedpnlbyclientsymbol{$clientforpnl}{$symbol}) {
1638 my $existingpnl = $closedpnlbyclientsymbol{$clientforpnl}{$symbol};
1639 DebugPrintOut("Existing PNL pre-transfer for $clientforpnl:$symbol is: $existingpnl\n");
1640 $existingpnl = $existingpnl + $closedpnl;
1641 $closedpnlbyclientsymbol{$clientforpnl}{$symbol} = $existingpnl;
1642 DebugPrintOut("New total pnl after transfer for $clientforpnl:$symbol is: $existingpnl\n");
1643 }
1644 else {
1645 $closedpnlbyclientsymbol{$clientforpnl}{$symbol} = $closedpnl;
1646 DebugPrintOut("New total pnl for $clientforpnl:$symbol is: $closedpnl\n");
1647 }
1648
1649 my $storedpnlnumber = $closedpnlbyclientsymbol{$clientforpnl}{$symbol};
1650 #PrintOut("CONTRA: ($clientforpnl:$closedpnl) -- $contratime: $clientforpnl:$symbol:$contraendpoint $contraside $contrafifoposition @ $contrafifoprice --> $contrapositionid --> $idforpnl\n");
1651 PrintOut("ECONTRA: P&L: ($clientforpnl:$symbol:$closedpnl:$storedpnlnumber) -- ($contraside/$side) $minqty $symbol @ ($contrafifoprice/$lastfillprice) ($idforpnl/$origmsgid) in client $client\n");
1652
1653 # Check to see if we should exit the loop at this point in the transaction
1654 if($shouldexitloop == 1) {
1655 $shouldexitloop = 0;
1656 last;
1657 }
1658
1659 # Update the last fill quantity
1660 $lastfillquantity = $lastfillquantity - $contrafifoposition;
1661 }
1662 else {
1663 PrintOut("No positions on other side to transact against. Injecting position into this side's position queue!\n");
1664 my @samepositionarray;
1665
1666 # We no longer have any positions on the contra side.
1667 # Put the remaining last fill quantity on the same side as an open position,
1668 # at the end of the queue.
1669 if(exists ${$sameposreference}{$client} and defined ${$sameposreference}{$client}{$symbol}) {
1670 # We don't have any existing positions on the same side
1671 @samepositionarray = @{$$sameposreference{$client}{$symbol}};
1672 }
1673 else {
1674 @samepositionarray = ();
1675 }
1676
1677 # We need to generate new positions to put into the map
1678 my $insertposition = new TradePosition;
1679 $insertposition->positionid($fillid);
1680 $insertposition->origmsgid($origmsgid);
1681 #$insertposition->timestring($tminusoneymd . "-" . $time);
1682 $insertposition->timestring($time);
1683 $insertposition->positionpx($lastfillprice);
1684 $insertposition->origqty($originalquantity);
1685 $insertposition->leavesqty($lastfillquantity);
1686 $insertposition->client($client);
1687 $insertposition->account($account);
1688 $insertposition->symbol($symbol);
1689 $insertposition->side($side);
1690 $insertposition->endpoint($endpoint);
1691 $insertposition->prodmultiplier($prodmultiplier);
1692 $insertposition->xchangerate($xchangerate);
1693 $insertposition->origclient($client);
1694 $insertposition->clearcharge($clearcharge);
1695 $insertposition->exchangecharge($exchangecharge);
1696 $insertposition->liquiditycharge($liquiditycharge);
1697 $insertposition->seccharge($seccharge);
1698 $insertposition->nfacharge($nfacharge);
1699 $insertposition->bfexorigqtys(());
1700 $insertposition->bfexsizes(());
1701 $insertposition->bfexprices(());
1702 $insertposition->bfexposids(());
1703 $insertposition->bfexorigids(());
1704 $insertposition->bfexclearcharges(());
1705 $insertposition->bfexexchangecharges(());
1706 $insertposition->bfexliquiditycharges(());
1707 $insertposition->bfexseccharges(());
1708 $insertposition->bfexnfacharges(());
1709 $insertposition->bfexorigclients(());
1710 $insertposition->bfexxchangerates(());
1711 $insertposition->bfexendpoints(());
1712 #$insertposition->bfexdates(());
1713 #$insertposition->positiondate($todaysymd);
1714 push(@samepositionarray, $insertposition);
1715
1716 # Re-insert the position
1717 $$sameposreference{$client}{$symbol} = \@samepositionarray;
1718
1719 # Reset last fill quantity just in case
1720 $lastfillquantity = 0;
1721
1722 # Exit this loop.
1723 last;
1724 }
1725 }
1726 }
1727 # If we don’t have any contra positions period, add the fill as a complete open position on the same side. (5)
1728 else {
1729 PrintOut("Zero positions on other side to transact against. Injecting position into this side's position queue!\n");
1730 my @samepositionarray;
1731
1732 # We don't have an existing contra position
1733 # We have to add this to the existing positions on this side.
1734 if(exists ${$sameposreference}{$client} and defined ${$sameposreference}{$client}{$symbol}) {
1735 DebugPrintOut("Appending to existing postions!!\n");
1736 # We don't have any existing positions on the same side
1737 @samepositionarray = @{$$sameposreference{$client}{$symbol}};
1738 }
1739 else {
1740 DebugPrintOut("No same positions detected! Generating new postion set and adding!\n");
1741 @samepositionarray = ();
1742 }
1743
1744 # We need to generate new positions to put into the map
1745 my $insertposition = new TradePosition;
1746 $insertposition->positionid($fillid);
1747 $insertposition->origmsgid($origmsgid);
1748 #$insertposition->timestring($tminusoneymd . "-" . $time);
1749 $insertposition->timestring($time);
1750 $insertposition->positionpx($lastfillprice);
1751 $insertposition->origqty($lastfillquantity);
1752 $insertposition->leavesqty($lastfillquantity);
1753 $insertposition->client($client);
1754 $insertposition->account($account);
1755 $insertposition->symbol($symbol);
1756 $insertposition->side($side);
1757 $insertposition->endpoint($endpoint);
1758 $insertposition->prodmultiplier($prodmultiplier);
1759 $insertposition->origclient($client);
1760 $insertposition->clearcharge($clearcharge);
1761 $insertposition->exchangecharge($exchangecharge);
1762 $insertposition->liquiditycharge($liquiditycharge);
1763 $insertposition->seccharge($seccharge);
1764 $insertposition->nfacharge($nfacharge);
1765 $insertposition->xchangerate($xchangerate);
1766 $insertposition->bfexorigqtys(());
1767 $insertposition->bfexsizes(());
1768 $insertposition->bfexprices(());
1769 $insertposition->bfexposids(());
1770 $insertposition->bfexorigids(());
1771 $insertposition->bfexclearcharges(());
1772 $insertposition->bfexexchangecharges(());
1773 $insertposition->bfexliquiditycharges(());
1774 $insertposition->bfexseccharges(());
1775 $insertposition->bfexnfacharges(());
1776 $insertposition->bfexorigclients(());
1777 $insertposition->bfexxchangerates(());
1778 $insertposition->bfexendpoints(());
1779 #$insertposition->bfexdates(());
1780 #$insertposition->positiondate($todaysymd);
1781
1782 # Push the TradePosition object into the array
1783 push(@samepositionarray, $insertposition);
1784
1785 $$sameposreference{$client}{$symbol} = \@samepositionarray;
1786 }
1787
1788 # Print out new client position summary
1789 my $currentclisymposition = 0;
1790 if(exists $openlongpositionbyclientsymbol{$client} and defined $openlongpositionbyclientsymbol{$client}{$symbol}) {
1791 my @longarray = @{$openlongpositionbyclientsymbol{$client}{$symbol}};
1792 foreach (@longarray) {
1793 my $longpositionobject = $_;
1794 my $longposition = $longpositionobject->leavesqty;
1795 $currentclisymposition += $longposition;
1796 }
1797 }
1798 if(exists $openshortpositionbyclientsymbol{$client} and defined $openshortpositionbyclientsymbol{$client}{$symbol}) {
1799 my @shortarray = @{$openshortpositionbyclientsymbol{$client}{$symbol}};
1800 foreach (@shortarray) {
1801 my $shortpositionobject = $_;
1802 my $shortposition = $shortpositionobject->leavesqty;
1803 $currentclisymposition -= $shortposition;
1804 }
1805 }
1806 DebugPrintOut("CURRENT POSITION FOR $client:$symbol is: $currentclisymposition\n");
1807
1808 # Reset Variables - Just In Case
1809 ResetVars();
1810
1811 # Print out the contents of each open position hash at the end
1812 #print "LONG POSITIONS BY CLIENT/SYMBOL: \n";
1813 #PrintPositionMap(\%openlongpositionbyclientsymbol);
1814 #print "SHORT POSITIONS BY CLIENT\SYMBOL: \n";
1815 #PrintPositionMap(\%openshortpositionbyclientsymbol);
1816
1817 PrintOut("==========================================\n");
1818}
1819
1820# Check to see if we have a real time loop
1821if($runmode eq "RealTime") {
1822 # Generate Lines For Each PNL Instance
1823 GenerateRealTimePNLFile();
1824
1825 # Sleep, rinse, repeat
1826 sleep 5;
1827 goto REALTIMELOOP;
1828}
1829
1830# Flush out any debts that we have remaining from ledger transactions.
1831PrintOutStd("==========================================\n");
1832PrintOutStd("FLUSHING DEBTS!\n");
1833PrintOutStd("==========================================\n");
1834
1835# At the end of the day, check the debts and enforce them
1836foreach my $debtpos (@debtqueue) {
1837 # We have long debt to transfer out for a client.
1838 # Execute!
1839 my $destclient = $debtpos->client;
1840 my $debtamount = $debtpos->leavesqty;
1841 my $clientkey = $debtpos->origclient;
1842 my $symbolkey = $debtpos->symbol;
1843 my $debtside = $debtpos->side;
1844 my $samedebtpullref = (($debtside =~ "B") ? \%openlongpositionbyclientsymbol : \%openshortpositionbyclientsymbol);
1845 my $sidedisplay = (($debtside =~ "B") ? "long" : "short");
1846
1847 # Notate original positions
1848 PrintOutStd("Debt found for $clientkey:$symbolkey for $debtamount, to send to $destclient!\n");
1849 my $originatingpos = GetTotalPositionForClientSymbol($clientkey, $symbolkey);
1850 my $destinationpos = GetTotalPositionForClientSymbol($destclient, $symbolkey);
1851 PrintOutStd("Pre-Debt Position for $clientkey:$symbolkey is $originatingpos\n");
1852 PrintOutStd("Pre-Debt Position for $destclient:$symbolkey is $destinationpos\n");
1853
1854 if(exists $$samedebtpullref{$clientkey} and defined $$samedebtpullref{$clientkey}{$symbolkey}) {
1855 # Grab the positions to transfer and check the size
1856 my @posarr = @{$$samedebtpullref{$clientkey}{$symbolkey}};
1857 my $positiontotal = 0;
1858 foreach my $currpos (@posarr) {
1859 my $currposleaves = $currpos->leavesqty;
1860 $positiontotal += $currposleaves;
1861 }
1862 if($positiontotal < $debtamount) {
1863 PrintOutStd("ERROR: Not enough $sidedisplay position exists in $clientkey to transfer out! Exiting!\n");
1864 #die("ERROR: Not enough $sidedisplay position exists in $clientkey to transfer out! Exiting!\n");
1865 ErrorAndShutdown("ERROR: Not enough $sidedisplay position exists in $clientkey to transfer out! Exiting!\n");
1866 }
1867
1868 # If we've gotten to this point, we know that we have enough to transfer out
1869 while($debtamount > 0) {
1870 my $currpos = shift(@posarr);
1871 my $currposid = $currpos->positionid();
1872 my $currposorigid = $currpos->origmsgid();
1873 my $currpostime = $currpos->timestring();
1874 my $currpospx = $currpos->positionpx();
1875 my $currposorigqty = $currpos->origqty();
1876 my $currposleaves = $currpos->leavesqty();
1877 my $currposorigclient = $currpos->origclient();
1878 my $currposclearcharge = $currpos->clearcharge();
1879 my $currposexchangecharge = $currpos->exchangecharge();
1880 my $currposliquiditycharge = $currpos->liquiditycharge();
1881 my $currposseccharge = $currpos->seccharge();
1882 my $currposnfacharge = $currpos->nfacharge();
1883 my $currposaccount = $currpos->account();
1884 my $currposendpoint = $currpos->endpoint();
1885 my $currposmult = $currpos->prodmultiplier();
1886 my $currposrate = $currpos->xchangerate();
1887 #my $currposdate = $currpos->positiondate();
1888 if($currposleaves >= $debtamount) {
1889 # We're essentially splitting this position in two.
1890 my $copyposition = new TradePosition;
1891 $copyposition->positionid($currposid);
1892 $copyposition->origmsgid($currposorigid);
1893 $copyposition->timestring($currpostime);
1894 $copyposition->positionpx($currpospx);
1895 $copyposition->origqty($currposorigqty);
1896 $copyposition->leavesqty($debtamount);
1897 $copyposition->client($destclient);
1898 $copyposition->account($currposaccount);
1899 $copyposition->symbol($symbolkey);
1900 $copyposition->side($debtside);
1901 $copyposition->endpoint($currposendpoint);
1902 $copyposition->prodmultiplier($currposmult);
1903 $copyposition->xchangerate($currposrate);
1904 $copyposition->origclient($destclient);
1905 $copyposition->clearcharge($currposclearcharge);
1906 $copyposition->exchangecharge($currposexchangecharge);
1907 $copyposition->liquiditycharge($currposliquiditycharge);
1908 $copyposition->seccharge($currposseccharge);
1909 $copyposition->nfacharge($currposnfacharge);
1910 $copyposition->bfexorigqtys(());
1911 $copyposition->bfexsizes(());
1912 $copyposition->bfexprices(());
1913 $copyposition->bfexposids(());
1914 $copyposition->bfexorigids(());
1915 $copyposition->bfexclearcharges(());
1916 $copyposition->bfexexchangecharges(());
1917 $copyposition->bfexliquiditycharges(());
1918 $copyposition->bfexseccharges(());
1919 $copyposition->bfexnfacharges(());
1920 $copyposition->bfexorigclients(());
1921 $copyposition->bfexxchangerates(());
1922 $copyposition->bfexendpoints(());
1923 #$copyposition->bfexdates(());
1924 #$copyposition->positiondate($currposdate);
1925
1926 # Push this into the array;
1927 my @destclientposarr;
1928 if(exists $$samedebtpullref{$destclient} and defined $$samedebtpullref{$destclient}{$symbolkey}) {
1929 @destclientposarr = @{$$samedebtpullref{$destclient}{$symbolkey}};
1930 }
1931 else {
1932 @destclientposarr = ();
1933 }
1934 push(@destclientposarr,$copyposition);
1935 $$samedebtpullref{$destclient}{$symbolkey} = \@destclientposarr;
1936
1937 # We have enough to cover the rest of the debt in this one position.
1938 # Take what we need to, and put the rest back.
1939 if($currposleaves != $debtamount) {
1940 $currposleaves -= $debtamount;
1941 $currpos->leavesqty($currposleaves);
1942 unshift(@posarr, $currpos);
1943 }
1944
1945 # Cancel out the debt
1946 $debtamount = 0;
1947 }
1948 else {
1949 # We don't have enough to cover the rest of the debt. Transfer off this entire position.
1950 # Leave the origclient as is.
1951 $currpos->client($destclient);
1952
1953 # Push this into the array;
1954 my @destclientposarr;
1955 if(exists $$samedebtpullref{$destclient} and defined $$samedebtpullref{$destclient}{$symbolkey}) {
1956 @destclientposarr = @{$$samedebtpullref{$destclient}{$symbolkey}};
1957 }
1958 else {
1959 @destclientposarr = ();
1960 }
1961 push(@destclientposarr,$currpos);
1962 $$samedebtpullref{$destclient}{$symbolkey} = \@destclientposarr;
1963
1964 # Refresh the debt amount
1965 $debtamount -= $currposleaves;
1966 }
1967 }
1968
1969 # Re-assign the position array minus the transferred out positions.
1970 $$samedebtpullref{$clientkey}{$symbolkey} = \@posarr;
1971
1972 # Transact crosses post-transfer in case we're adding shorts to a total long, or
1973 # longs to a total short
1974 TransactCrosses($destclient,$symbolkey,$clientkey);
1975 }
1976 else {
1977 PrintOutStd("ERROR: No long positions exist in $clientkey to transfer out! Exiting!\n");
1978 #die("ERROR: No long positions exist in $clientkey to transfer out! Exiting!\n");
1979 ErrorAndShutdown("ERROR: No long positions exist in $clientkey to transfer out! Exiting!\n");
1980 }
1981
1982 my $endoriginatingpos = GetTotalPositionForClientSymbol($clientkey, $symbolkey);
1983 my $enddestinationpos = GetTotalPositionForClientSymbol($destclient, $symbolkey);
1984 PrintOutStd("End Position for $clientkey:$symbolkey is $endoriginatingpos\n");
1985 PrintOutStd("End Position for $destclient:$symbolkey is $enddestinationpos\n");
1986}
1987
1988PrintOutStd("==========================================\n");
1989
1990PrintOutStd("==========================================\n");
1991PrintOutStd("CHECKING ADDED BFEX TRANSACTIONS\n");
1992PrintOutStd("==========================================\n");
1993foreach my $bfexstring (@bfexactions) {
1994 # Processing BFEX action
1995 $bfexstring =~ s/^\s+|\s+$//g;
1996 PrintOutStd("Processing BFEX action: $bfexstring\n");
1997
1998 # Action string should be:
1999 # push(@currentledgeractions, "ADDBFEX $sidechoice $qtychoice $symbolchoice $pxchoice $origclichoice $destclichoice");
2000 my @actionsplitter = split " ", $bfexstring;
2001 my $sidechoice = $actionsplitter[1];
2002 my $qtychoice = $actionsplitter[2];
2003 my $symbolchoice = $actionsplitter[3];
2004 my $pxchoice = $actionsplitter[4];
2005 my $origclichoice = $actionsplitter[5];
2006 my $destclichoice = $actionsplitter[6];
2007 my $contrasidechoice = GetContraSide($sidechoice);
2008
2009 # Grab the prod multiplier and exchange rate from the originating client
2010 my $prodmultchoice;
2011 my $xchangeratechoice;
2012 my $posmapreference = (($sidechoice =~ "B") ? \%openlongpositionbyclientsymbol : \%openshortpositionbyclientsymbol);
2013 my $contraposmapreference = (($sidechoice =~ "B") ? \%openshortpositionbyclientsymbol : \%openlongpositionbyclientsymbol);
2014 if(exists $$contraposmapreference{$origclichoice} and defined $$contraposmapreference{$origclichoice}{$symbolchoice}) {
2015 my @posarr = @{$$contraposmapreference{$origclichoice}{$symbolchoice}};
2016 my $posarrsize = @posarr;
2017 if($posarrsize > 0) {
2018 my $firstposition = @posarr[0];
2019 $prodmultchoice = $firstposition->prodmultiplier;
2020 $xchangeratechoice = $firstposition->xchangerate;
2021 }
2022 }
2023 else {
2024 if(exists $$posmapreference{$origclichoice} and defined $$posmapreference{$origclichoice}{$symbolchoice}) {
2025 my @posarr = @{$$posmapreference{$origclichoice}{$symbolchoice}};
2026 my $posarrsize = @posarr;
2027 if($posarrsize > 0) {
2028 my $firstposition = @posarr[0];
2029 $prodmultchoice = $firstposition->prodmultiplier;
2030 $xchangeratechoice = $firstposition->xchangerate;
2031 }
2032 }
2033 }
2034
2035 # If we haven't found any data, die with a warning.
2036 if(undef $prodmultchoice) {
2037 PrintOutStd("No available data to extract exchange rate and product multiplier data!\n");
2038 PrintOutStd("Failed to extract exchange rate and product multiplier data for a BFEX transaction for symbol $symbolchoice from $origclichoice on side $sidechoice!\n");
2039 die;
2040 }
2041
2042 # Generate BFEX positions for both clients and add them.
2043 my $origbfex = new TradePosition;
2044 $origbfex->positionid("MANUALENTRY");
2045 $origbfex->origmsgid("MANUALENTRY");
2046 $origbfex->timestring("2099-01-01 12:53:38.120");
2047 $origbfex->positionpx($pxchoice);
2048 $origbfex->origqty($qtychoice);
2049 $origbfex->leavesqty($qtychoice);
2050 $origbfex->client($origclichoice);
2051 $origbfex->account("UNWN");
2052 $origbfex->symbol($symbolchoice);
2053 $origbfex->side($sidechoice);
2054 $origbfex->endpoint("UNWN");
2055 $origbfex->prodmultiplier($prodmultchoice);
2056 $origbfex->xchangerate($xchangeratechoice);
2057 $origbfex->origclient($origclichoice);
2058 $origbfex->clearcharge(0);
2059 $origbfex->exchangecharge(0);
2060 $origbfex->liquiditycharge(0);
2061 $origbfex->seccharge(0);
2062 $origbfex->nfacharge(0);
2063 $origbfex->bfexorigqtys(());
2064 $origbfex->bfexsizes(());
2065 $origbfex->bfexprices(());
2066 $origbfex->bfexposids(());
2067 $origbfex->bfexorigids(());
2068 $origbfex->bfexclearcharges(());
2069 $origbfex->bfexexchangecharges(());
2070 $origbfex->bfexliquiditycharges(());
2071 $origbfex->bfexseccharges(());
2072 $origbfex->bfexnfacharges(());
2073 $origbfex->bfexorigclients(());
2074 $origbfex->bfexxchangerates(());
2075 $origbfex->bfexendpoints(());
2076 #$origbfex->bfexdates(());
2077 #$origbfex->positiondate("20990101");
2078
2079 my $destbfex = new TradePosition;
2080 $destbfex->positionid("MANUALENTRY");
2081 $destbfex->origmsgid("MANUALENTRY");
2082 $destbfex->timestring("2099-01-01 12:53:38.120");
2083 $destbfex->positionpx($pxchoice);
2084 $destbfex->origqty($qtychoice);
2085 $destbfex->leavesqty($qtychoice);
2086 $destbfex->client($destclichoice);
2087 $destbfex->client("UNWN");
2088 $destbfex->symbol($symbolchoice);
2089 $destbfex->side($contrasidechoice);
2090 $destbfex->endpoint("UNWN");
2091 $destbfex->prodmultiplier($prodmultchoice);
2092 $destbfex->xchangerate($xchangeratechoice);
2093 $destbfex->origclient($destclichoice);
2094 $destbfex->clearcharge(0);
2095 $destbfex->exchangecharge(0);
2096 $destbfex->liquiditycharge(0);
2097 $destbfex->seccharge(0);
2098 $destbfex->nfacharge(0);
2099 $destbfex->bfexorigqtys(());
2100 $destbfex->bfexsizes(());
2101 $destbfex->bfexprices(());
2102 $destbfex->bfexposids(());
2103 $destbfex->bfexorigids(());
2104 $destbfex->bfexclearcharges(());
2105 $destbfex->bfexexchangecharges(());
2106 $destbfex->bfexliquiditycharges(());
2107 $destbfex->bfexseccharges(());
2108 $destbfex->bfexnfacharges(());
2109 $destbfex->bfexorigclients(());
2110 $destbfex->bfexxchangerates(());
2111 $destbfex->bfexendpoints(());
2112 #$destbfex->bfexdates(());
2113 #$destbfex->positiondate("20990101");
2114
2115 # Bit of redundant work here.
2116 my @origexentryarr;
2117 my @destexentryarr;
2118 if(exists $$posmapreference{$origclichoice} and defined $$posmapreference{$origclichoice}{$symbolchoice}) {
2119 @origexentryarr = @{$$posmapreference{$origclichoice}{$symbolchoice}};
2120 }
2121 else {
2122 @origexentryarr = ();
2123 }
2124 PrintOutStd("Pushing BFEX of $sidechoice $qtychoice $symbolchoice @ $pxchoice into $origclichoice\n");
2125 push(@origexentryarr, $origbfex);
2126 $$posmapreference{$origclichoice}{$symbolchoice} = \@origexentryarr;
2127
2128 my @destexentryarr;
2129 my @destexentryarr;
2130 if(exists $$contraposmapreference{$destclichoice} and defined $$contraposmapreference{$destclichoice}{$symbolchoice}) {
2131 @destexentryarr = @{$$contraposmapreference{$destclichoice}{$symbolchoice}};
2132 }
2133 else {
2134 @destexentryarr = ();
2135 }
2136 PrintOutStd("Pushing BFEX of $contrasidechoice $qtychoice $symbolchoice @ $pxchoice into $destclichoice\n");
2137 push(@destexentryarr, $destbfex);
2138 $$contraposmapreference{$destclichoice}{$symbolchoice} = \@destexentryarr;
2139}
2140PrintOutStd("==========================================\n");
2141
2142# Store our fills
2143PrintOutStd("Beginning archive of today's fills into $fillsfilecheck!\n");
2144# Open the file for writing today's fills
2145open(FILLSARCHIVE, ">" , "$fillsfilecheck") || die "Failed to open file for writing today's fills at $fillsfilecheck!\n";
2146FILLSARCHIVE->autoflush;
2147foreach my $fillstring (@fillwritestrings) {
2148 print FILLSARCHIVE "$fillstring\n";
2149}
2150PrintOutStd("Fills archiving completed!\n");
2151
2152# Spacing
2153PrintOut("\n");
2154PrintOut("\n");
2155PrintOut("\n");
2156PrintOut("\n");
2157PrintOut("\n");
2158PrintOut("\n");
2159PrintOut("\n");
2160PrintOut("\n");
2161PrintOut("\n");
2162PrintOut("\n");
2163PrintOut("\n");
2164PrintOut("\n");
2165
2166PrintOut("=========================================================\n");
2167PrintOut("FINAL SANITY CHECKS\n");
2168PrintOut("=========================================================\n");
2169#######################################
2170# BFEX ZERO OUT SANITY
2171#######################################
2172
2173# Check to see if we have any BFEX transactions remaining in queue.
2174# This should not happen. If it does, error out!
2175my $bfexlonghashsize = 0;
2176my $bfexshorthashsize = 0;
2177
2178# Iterate through the internal cross hashes and add up sizes
2179foreach my $symkey (keys %openlongintexbysymbol) {
2180 my @symbolarr = @{$openlongintexbysymbol{$symkey}};
2181 foreach (@symbolarr) {
2182 $bfexlonghashsize++;
2183 }
2184}
2185
2186foreach my $symkey (keys %openshortintexbysymbol) {
2187 my @symbolarr = @{$openshortintexbysymbol{$symkey}};
2188 foreach (@symbolarr) {
2189 $bfexshorthashsize++;
2190 }
2191}
2192
2193# Go fatal if we have any internal cross remnants.
2194if($bfexlonghashsize > 0) {
2195 PrintOutStd("FINAL SANITY CHECK FAILURE! We still have $bfexlonghashsize internal cross long sizes remaining:\n");
2196 foreach my $symkey (keys %openlongintexbysymbol) {
2197 my @symbolcheck = @{$openlongintexbysymbol{$symkey}};
2198 foreach (@symbolcheck) {
2199 my $longintexposition = $_;
2200 my $intexpositionid = $longintexposition->positionid;
2201 my $intexpositionqty = $longintexposition->leavesqty;
2202 PrintOut("$intexpositionqty ($intexpositionid)\n");
2203 }
2204 }
2205 die;
2206}
2207
2208if($bfexshorthashsize > 0) {
2209 PrintOutStd("FINAL SANITY CHECK FAILURE! We still have $bfexshorthashsize internal cross short sizes remaining:\n");
2210 foreach my $symkey (keys %openshortintexbysymbol) {
2211 my @symbolarr = @{$openshortintexbysymbol{$symkey}};
2212 foreach (@symbolarr) {
2213 my $shortintexposition = $_;
2214 my $intexpositionid = $shortintexposition->positionid;
2215 my $intexpositionqty = $shortintexposition->leavesqty;
2216 PrintOut("$intexpositionqty ($intexpositionid)\n");
2217 }
2218 }
2219 die;
2220}
2221
2222if(($bfexlonghashsize == 0) && ($bfexshorthashsize == 0)) {
2223 PrintOut("FINAL SANITY CHECK PASSED: Internal cross transactions have been zeroed out!\n");
2224}
2225
2226#######################################
2227# EOD POSITION CHECK SANITY
2228#######################################
2229my %clientsymbolpositiontotal = ();
2230# Total up the positions
2231foreach my $clientkey (keys %openlongpositionbyclientsymbol) {
2232 my %symbolhash = %{$openlongpositionbyclientsymbol{$clientkey}};
2233 foreach my $symbolkey (keys %symbolhash) {
2234 my @longposarr = @{$openlongpositionbyclientsymbol{$clientkey}{$symbolkey}};
2235 foreach my $currpos (@longposarr) {
2236 my $currposleaves = $currpos->leavesqty;
2237 if(exists $clientsymbolpositiontotal{$clientkey} and defined $clientsymbolpositiontotal{$clientkey}{$symbolkey}) {
2238 my $existingtotal = $clientsymbolpositiontotal{$clientkey}{$symbolkey};
2239 $existingtotal += $currposleaves;
2240 $clientsymbolpositiontotal{$clientkey}{$symbolkey} = $existingtotal;
2241 }
2242 else {
2243 my $existingtotal = 0;
2244 $existingtotal += $currposleaves;
2245 $clientsymbolpositiontotal{$clientkey}{$symbolkey} = $existingtotal;
2246 }
2247 }
2248 }
2249}
2250foreach my $clientkey (keys %openshortpositionbyclientsymbol) {
2251 my %symbolhash = %{$openshortpositionbyclientsymbol{$clientkey}};
2252 foreach my $symbolkey (keys %symbolhash) {
2253 my @shortposarr = @{$openshortpositionbyclientsymbol{$clientkey}{$symbolkey}};
2254 foreach my $currpos (@shortposarr) {
2255 my $currposleaves = $currpos->leavesqty;
2256 if(exists $clientsymbolpositiontotal{$clientkey} and defined $clientsymbolpositiontotal{$clientkey}{$symbolkey}) {
2257 my $existingtotal = $clientsymbolpositiontotal{$clientkey}{$symbolkey};
2258 $existingtotal -= $currposleaves;
2259 $clientsymbolpositiontotal{$clientkey}{$symbolkey} = $existingtotal;
2260 }
2261 else {
2262 my $existingtotal = 0;
2263 $existingtotal -= $currposleaves;
2264 $clientsymbolpositiontotal{$clientkey}{$symbolkey} = $existingtotal;
2265 }
2266 }
2267 }
2268}
2269
2270my $eodposmatchdb = 1;
2271my $poscheck_str = "SELECT * FROM ( SELECT symbol,client,SUM(eodposition) as position FROM endofday WHERE convert(varchar,tradedate,112) = '$todaysymd' GROUP BY symbol,client) a WHERE (a.position != 0) ORDER BY client, symbol ASC";
2272my $poscheck_proc = $dbh->prepare($poscheck_str);
2273$poscheck_proc->execute;
2274my $posdata = $poscheck_proc->fetchall_arrayref;
2275my $possymbol;
2276my $posclient;
2277my $posposition;
2278my $needsresweep;
2279my %secondconfirmmap = ();
2280my %confirmedpositions = ();
2281my @problemqueue = ();
2282foreach my $row (@$posdata) {
2283 $possymbol = $row->[0];
2284 $posclient = $row->[1];
2285 $posposition = $row->[2];
2286
2287 # Put this immediately into the second confirmation map - Comparison against the database
2288 $secondconfirmmap{$posclient}{$possymbol} = $posposition;
2289
2290 # Iterate through and check
2291 if(exists $clientsymbolpositiontotal{$posclient} and defined $clientsymbolpositiontotal{$posclient}{$possymbol}) {
2292 my $totaldata = $clientsymbolpositiontotal{$posclient}{$possymbol};
2293 if($totaldata != $posposition) {
2294 push(@problemqueue, "CRITICAL ERROR: Unresolved EOD mismatch for $posclient : $possymbol --> EOD has $posposition, we have $totaldata!\n");
2295 next;
2296 }
2297 # Move this key from the hash once we've verified it
2298 $confirmedpositions{$posclient}{$possymbol} = $totaldata;
2299 delete $clientsymbolpositiontotal{$posclient}{$possymbol};
2300
2301 # Clean hash if necessary
2302 my %remkeyscheck = %{$clientsymbolpositiontotal{$posclient}};
2303 my $remkeyssize = keys %remkeyscheck;
2304 if($remkeyssize == 0) {
2305 delete $clientsymbolpositiontotal{$posclient};
2306 }
2307 }
2308 else {
2309 push(@problemqueue, "CRITICAL ERROR: Couldn't find matching EOD entry for $possymbol / $posclient! Should have a position of $posposition!\n");
2310 next;
2311 }
2312}
2313
2314# Clean up zero positions
2315foreach my $clientkey (sort keys %clientsymbolpositiontotal) {
2316 my %symbolhashes = %{$clientsymbolpositiontotal{$clientkey}};
2317 foreach my $symbolkey (sort keys %symbolhashes) {
2318 my $positioncheck = $clientsymbolpositiontotal{$clientkey}{$symbolkey};
2319 if($positioncheck == 0) {
2320 delete $clientsymbolpositiontotal{$clientkey}{$symbolkey};
2321 my $secondpositioncheck = keys %{$clientsymbolpositiontotal{$clientkey}};
2322 if($secondpositioncheck == 0) {
2323 delete $clientsymbolpositiontotal{$clientkey};
2324 }
2325 }
2326 }
2327}
2328
2329my $remainingsize = keys %clientsymbolpositiontotal;
2330if($remainingsize > 0) {
2331 push(@problemqueue, "CRITICAL ERROR: BI-DIRECTIONAL MATCH FAILURE FOR EOD! We still have the following un-resolved positions in our map:\n");
2332 foreach my $clientkey (sort keys %clientsymbolpositiontotal) {
2333 my %symbolhashes = %{$clientsymbolpositiontotal{$clientkey}};
2334 foreach my $symbolkey (sort keys %symbolhashes) {
2335 my $positioncheck = $clientsymbolpositiontotal{$clientkey}{$symbolkey};
2336 push(@problemqueue,"\t$clientkey:$symbolkey:$positioncheck\n");
2337 }
2338 }
2339}
2340
2341# Print out the EOD conflicts and die.
2342my $problemqueuesize = @problemqueue;
2343if($problemqueuesize > 0) {
2344 my $endproblemqueue = "";
2345 foreach my $problemstring (@problemqueue) {
2346 PrintOutStd($problemstring);
2347 $endproblemqueue = $endproblemqueue . $problemstring;
2348 }
2349 ErrorAndShutdown($endproblemqueue);
2350 die;
2351}
2352
2353# If we've reached here, we've passed
2354PrintOut("FINAL SANITY CHECK PASSED: Internal EOD positions match the database!\n");
2355
2356# =========================================================
2357# FINAL PRINTOUTS FOR ANALYSIS / RESTORATION
2358# =========================================================
2359# Print actual positions
2360PrintOut("==========================================\n");
2361PrintOut(" FINAL POSITIONS\n");
2362PrintOut("==========================================\n");
2363PrintOut("LONG POSITIONS BY CLIENT/SYMBOL: \n");
2364PrintPositionMap(\%openlongpositionbyclientsymbol);
2365PrintOut("SHORT POSITIONS BY CLIENT\SYMBOL: \n");
2366PrintPositionMap(\%openshortpositionbyclientsymbol);
2367PrintOut("==========================================\n");
2368PrintOut("\n");
2369PrintOut("\n");
2370PrintOut("\n");
2371PrintOut("\n");
2372# Print Closed PNL
2373PrintOut("==========================================\n");
2374PrintOut("FINAL CLOSED PNL\n");
2375PrintOut("==========================================\n");
2376# Define database variables
2377my $insdbuser = 'php' ;
2378my $insdbpasswd = 'vodka66';
2379my $insdbserver = 'sv-chof-bfrp';
2380my $insdbname = 'Trading';
2381#
2382# Establish connection to the database
2383my $insdbh=DBI->connect("DBI:Sybase:$insdbserver",$insdbuser,$insdbpasswd) or die "Cant connect to DB!!\n";
2384$insdbh->do("use $dbname") or die "Cannot connect to $dbname on $dbserver!\n";
2385my $ins_str;
2386my $ins_proc;
2387my $ins_data;
2388
2389
2390# First, delete the old closed PNL from the database
2391$ins_str = "DELETE FROM pnlactual WHERE CONVERT(varchar, tradeDate, 112)='$todaysymd'";
2392$ins_proc = $insdbh->prepare($ins_str);
2393$ins_proc->execute;
2394
2395# Iterate and insert closed PNL into the database
2396foreach my $key (sort keys %closedpnlbyclientsymbol) {
2397 my $clientpnldata = 0;
2398 my %symbolhashes = %{$closedpnlbyclientsymbol{$key}};
2399 foreach my $symkey (sort keys %symbolhashes) {
2400 my $closedpnl = $symbolhashes{$symkey};
2401 $clientpnldata += $closedpnl;
2402 }
2403
2404 my $roundedclientpnldata = sprintf('%.2f', $clientpnldata);
2405
2406 # Insert this PNL into the pnlactual database
2407 # Schema is:
2408 # tradeDate (date)
2409 # account (varchar(50))
2410 # client (varchar(50))
2411 # symbol (varchar(50))
2412 # trader (varchar(50))
2413 # endpoint (varchar(50))
2414 # pnl (decimal(18,2))
2415 if(!$testwritemode) {
2416 $ins_str = "INSERT INTO pnlactual VALUES('$todaysymd','$key','$roundedclientpnldata')";
2417 $ins_proc = $insdbh->prepare($ins_str);
2418 $ins_proc->execute;
2419 }
2420
2421 # Client PNL display
2422 PrintOut("Client $key Closed PNL: $roundedclientpnldata\n");
2423}
2424
2425DebugPrintOut("Initializing Open PNL calculations for Historical APNL\n");
2426
2427# Delete the old open settle and theo PNLs from the database
2428$ins_str = "DELETE FROM pnlActualOpenSettle WHERE CONVERT(varchar, tradeDate, 112)='$todaysymd'";
2429$ins_proc = $insdbh->prepare($ins_str);
2430$ins_proc->execute;
2431
2432$ins_str = "DELETE FROM pnlActualOpenTheo WHERE CONVERT(varchar, tradeDate, 112)='$todaysymd'";
2433$ins_proc = $insdbh->prepare($ins_str);
2434$ins_proc->execute;
2435
2436# Calculate the open PNL from positions by client
2437my %settlemarksmap = ();
2438my %theomarksmap = ();
2439my %opensettlepnlbyclient = ();
2440my %opentheopnlbyclient = ();
2441
2442# Iterate through the settle marks and theo marks and insert them into an internal map
2443$ins_str = "SELECT * FROM marks where convert(varchar,tradedate,112)='$todaysymd'";
2444$ins_proc = $insdbh->prepare($ins_str);
2445$ins_proc->execute;
2446$ins_data = $ins_proc->fetchall_arrayref;
2447
2448DebugPrintOut("Populating Settle Marks Map Data for Open PNL calculations!\n");
2449foreach my $row (@$ins_data) {
2450 my $marksym = $row->[0];
2451 my $markamt = $row->[2];
2452 DebugPrintOut("Inserting Settle Mark for $marksym: $markamt\n");
2453 $settlemarksmap{$marksym} = $markamt;
2454 PrintOut("Inserting Settle Mark for $marksym: $markamt\n");
2455}
2456
2457$ins_str = "SELECT * FROM theomarks where convert(varchar,tradedate,112)='$todaysymd'";
2458$ins_proc = $insdbh->prepare($ins_str);
2459$ins_proc->execute;
2460$ins_data = $ins_proc->fetchall_arrayref;
2461
2462foreach my $row (@$ins_data) {
2463 my $theomarksym = $row->[0];
2464 my $theomarkamt = $row->[2];
2465 DebugPrintOut("Inserting Theo Mark for $theomarksym: $theomarkamt\n");
2466 $theomarksmap{$theomarksym} = $theomarkamt;
2467 PrintOut("Inserting Theo Mark for $theomarksym: $theomarkamt\n");
2468}
2469
2470# Iterate through our existing open positions and mark open pnl to them
2471foreach my $clientkey (keys %openshortpositionbyclientsymbol) {
2472 my %symbolhash = %{$openshortpositionbyclientsymbol{$clientkey}};
2473 foreach my $symbolkey (keys %symbolhash) {
2474 my @shortposarray = @{$openshortpositionbyclientsymbol{$clientkey}{$symbolkey}};
2475 foreach my $currpos (@shortposarray) {
2476 my $currposamt = $currpos->leavesqty;
2477 my $currpospx = $currpos->positionpx;
2478 my $currposxrate = $currpos->xchangerate;
2479 my $currposorigclient = $currpos->origclient;
2480 my $settlesymmark;
2481 my $theosymmark;
2482
2483 # Only calculate open PNL if we have marks available, else, the open PNL will just be counted as zero.
2484 if(exists $settlemarksmap{$symbolkey}) {
2485 $settlesymmark = $settlemarksmap{$symbolkey};
2486 my $opensettlepnl = $currposamt * ($currpospx - $settlesymmark) / $currposxrate;
2487 if(exists $opensettlepnlbyclient{$clientkey}) {
2488 my $existingpnl = $opensettlepnlbyclient{$clientkey};
2489 $opensettlepnl = $opensettlepnl + $existingpnl;
2490 }
2491 $opensettlepnlbyclient{$currposorigclient} = $opensettlepnl;
2492 }
2493 if(exists $theomarksmap{$symbolkey}) {
2494 $theosymmark = $theomarksmap{$symbolkey};
2495 my $opentheopnl = $currposamt * ($currpospx - $theosymmark) / $currposxrate;
2496 if(exists $opentheopnlbyclient{$clientkey}) {
2497 my $existingpnl = $opentheopnlbyclient{$clientkey};
2498 $opentheopnl = $opentheopnl + $existingpnl;
2499 }
2500 $opentheopnlbyclient{$currposorigclient} = $opentheopnl;
2501 }
2502 }
2503 }
2504}
2505
2506# Iterate through our existing open positions and mark open pnl to them
2507foreach my $clientkey (keys %openlongpositionbyclientsymbol) {
2508 my %symbolhash = %{$openlongpositionbyclientsymbol{$clientkey}};
2509 foreach my $symbolkey (keys %symbolhash) {
2510 my @longposarray = @{$openlongpositionbyclientsymbol{$clientkey}{$symbolkey}};
2511 foreach my $currpos (@longposarray) {
2512 my $currposamt = $currpos->leavesqty;
2513 my $currpospx = $currpos->positionpx;
2514 my $currposxrate = $currpos->xchangerate;
2515 my $currposorigclient = $currpos->origclient;
2516 my $settlesymmark;
2517 my $theosymmark;
2518
2519 # Only calculate open PNL if we have marks available, else, the open PNL will just be counted as zero.
2520 if(exists $settlemarksmap{$symbolkey}) {
2521 $settlesymmark = $settlemarksmap{$symbolkey};
2522 my $opensettlepnl = $currposamt * ($settlesymmark - $currpospx) / $currposxrate;
2523 if(exists $opensettlepnlbyclient{$clientkey}) {
2524 my $existingpnl = $opensettlepnlbyclient{$clientkey};
2525 $opensettlepnl = $opensettlepnl + $existingpnl;
2526 }
2527 $opensettlepnlbyclient{$currposorigclient} = $opensettlepnl;
2528 }
2529 if(exists $theomarksmap{$symbolkey}) {
2530 $theosymmark = $theomarksmap{$symbolkey};
2531 my $opentheopnl = $currposamt * ($theosymmark - $currpospx) / $currposxrate;
2532 if(exists $opentheopnlbyclient{$clientkey}) {
2533 my $existingpnl = $opentheopnlbyclient{$clientkey};
2534 $opentheopnl = $opentheopnl + $existingpnl;
2535 }
2536 $opentheopnlbyclient{$currposorigclient} = $opentheopnl;
2537 }
2538 }
2539 }
2540}
2541
2542# Insert the final PNL amounts
2543foreach my $clientkey (keys %opensettlepnlbyclient) {
2544 my $opensettlepnl = $opensettlepnlbyclient{$clientkey};
2545 my $roundedsettlepnl = sprintf "%.2f", $opensettlepnl;
2546 $ins_str = "INSERT INTO pnlActualOpenSettle VALUES('$todaysymd','$clientkey','$roundedsettlepnl')";
2547 $ins_proc = $insdbh->prepare($ins_str);
2548 $ins_proc->execute;
2549}
2550
2551foreach my $clientkey (keys %opentheopnlbyclient) {
2552 my $opentheopnl = $opentheopnlbyclient{$clientkey};
2553 my $roundedtheopnl = sprintf "%.2f", $opentheopnl;
2554 $ins_str = "INSERT INTO pnlActualOpenTheo VALUES('$todaysymd','$clientkey','$roundedtheopnl')";
2555 $ins_proc = $insdbh->prepare($ins_str);
2556 $ins_proc->execute;
2557}
2558
2559# We want to archive the old open data from Actual PNL somewhere. Because Dan is relying on reading
2560# the tables for data, we're just going to move the data elsewhere. I really should have just given
2561# him an isolated view into the table, but that could have gotten messy as well.
2562$ins_str = "INSERT INTO pnlActualOpenSettleArchive SELECT * FROM pnlActualOpenSettle WHERE CONVERT(varchar, tradeDate, 112)='$tminusoneymd'";
2563$ins_proc = $insdbh->prepare($ins_str);
2564$ins_proc->execute;
2565
2566$ins_str = "INSERT INTO pnlActualOpenTheoArchive SELECT * FROM pnlActualOpenTheo WHERE CONVERT(varchar, tradeDate, 112)='$tminusoneymd'";
2567$ins_proc = $insdbh->prepare($ins_str);
2568$ins_proc->execute;
2569
2570# If we have reached this point, we have had a successful insertion. We have
2571# to eliminate the previous day's open because only one open PNL should be reflected at a time.
2572# We still do, however, want to preserve the amount for historical reference.
2573$ins_str = "DELETE FROM pnlActualOpenSettle WHERE CONVERT(varchar, tradeDate, 112)='$tminusoneymd'";
2574$ins_proc = $insdbh->prepare($ins_str);
2575$ins_proc->execute;
2576
2577$ins_str = "DELETE FROM pnlActualOpenTheo WHERE CONVERT(varchar, tradeDate, 112)='$tminusoneymd'";
2578$ins_proc = $insdbh->prepare($ins_str);
2579$ins_proc->execute;
2580
2581PrintOut("\n");
2582PrintOut("==========================================\n");
2583PrintOut("\n");
2584PrintOut("\n");
2585PrintOut("\n");
2586PrintOut("\n");
2587PrintOut("==========================================\n");
2588PrintOut("FINAL TOTAL FEES\n");
2589PrintOut("==========================================\n");
2590# Do the actual printout
2591foreach my $key (sort keys %totalfeebyclientsymbol) {
2592 my $clientfeedata = 0;
2593 my %symbolhashes = %{$totalfeebyclientsymbol{$key}};
2594 foreach my $symkey (sort keys %symbolhashes) {
2595 my $closedfee = $symbolhashes{$symkey};
2596 $clientfeedata += $closedfee;
2597 }
2598 my $roundedclientfeedata = sprintf('%.2f', $clientfeedata);
2599
2600 # Client fee display
2601 PrintOut("Client $key total fee: $roundedclientfeedata\n");
2602}
2603PrintOut("==========================================\n");
2604PrintOut("\n");
2605PrintOut("\n");
2606PrintOut("\n");
2607PrintOut("\n");
2608PrintOut("==========================================\n");
2609PrintOut("FINAL TOTAL POSITIONS\n");
2610PrintOut("==========================================\n");
2611# Do the actual printout
2612foreach my $clientkey (sort keys %confirmedpositions) {
2613 my %symbolhash = %{$confirmedpositions{$clientkey}};
2614 foreach my $symbolkey (sort keys %symbolhash) {
2615 my $clisymtotal = $confirmedpositions{$clientkey}{$symbolkey};
2616 if($clisymtotal != 0) {
2617 PrintOut("$clientkey : $symbolkey : $clisymtotal\n");
2618 }
2619 }
2620}
2621PrintOut("==========================================\n");
2622# Print open positions out to a file
2623my $todaysfile = "/datlib/actualpnl/positions." . $todaysymd . ".out";
2624if($testwritemode) {
2625 $todaysfile = "testpositions." . $todaysymd . ".out";
2626}
2627PrintOut("Writing open positions to $todaysfile\n");
2628open(ARCHIVEFILE, ">" , "$todaysfile") || print "Failed to open file for writing today's position at $todaysfile!\n";
2629ARCHIVEFILE->autoflush;
2630foreach my $key (keys %openlongpositionbyclientsymbol) {
2631 my %symbolhashes = %{$openlongpositionbyclientsymbol{$key}};
2632 foreach my $symkey (keys %symbolhashes) {
2633 ##print "\t\t$symkey:\n\t\t\t";
2634 my @sympos = @{$symbolhashes{$symkey}};
2635 foreach (@sympos) {
2636 my $thisposition = $_;
2637 my $origid = $thisposition->origmsgid;
2638 my $positionid = $thisposition->positionid;
2639 my $timestring = $thisposition->timestring;
2640 my $positionpx = $thisposition->positionpx;
2641 my $origqty = $thisposition->origqty;
2642 my $leavesqty = $thisposition->leavesqty;
2643 my $client = $thisposition->client;
2644 my $symbol = $thisposition->symbol;
2645 my $side = $thisposition->side;
2646 my $endpoint = $thisposition->endpoint;
2647 my $origclient = $thisposition->origclient;
2648 my $prodmultiplier = $thisposition->prodmultiplier;
2649 my $xchangerate = $thisposition->xchangerate;
2650 my $account = $thisposition->account;
2651 my $clearcharge = $thisposition->clearcharge;
2652 my $exchangecharge = $thisposition->exchangecharge;
2653 my $liquiditycharge = $thisposition->liquiditycharge;
2654 my $seccharge = $thisposition->seccharge;
2655 my $nfacharge = $thisposition->nfacharge;
2656 #my $positiondate = $thisposition->positiondate;
2657
2658 # Write this line to a file
2659 #my $writestring = "$timestring,$positionid,$origid,$positionpx,$origqty,$leavesqty,$client,$symbol,$side,$endpoint,$origclient,$prodmultiplier,$xchangerate,$account,$clearcharge,$exchangecharge,$liquiditycharge,$seccharge,$nfacharge,$positiondate";
2660 my $writestring = "$timestring,$positionid,$origid,$positionpx,$origqty,$leavesqty,$client,$symbol,$side,$endpoint,$origclient,$prodmultiplier,$xchangerate,$account,$clearcharge,$exchangecharge,$liquiditycharge,$seccharge,$nfacharge";
2661 $writestring =~ s/^\s*(.*?)\s*$/$1/;
2662 print ARCHIVEFILE "$writestring\n";
2663 }
2664 }
2665}
2666foreach my $key (keys %openshortpositionbyclientsymbol) {
2667 my %symbolhashes = %{$openshortpositionbyclientsymbol{$key}};
2668 foreach my $symkey (keys %symbolhashes) {
2669 ##print "\t\t$symkey:\n\t\t\t";
2670 my @sympos = @{$symbolhashes{$symkey}};
2671 foreach (@sympos) {
2672 my $thisposition = $_;
2673 my $origid = $thisposition->origmsgid;
2674 my $positionid = $thisposition->positionid;
2675 my $timestring = $thisposition->timestring;
2676 my $positionpx = $thisposition->positionpx;
2677 my $origqty = $thisposition->origqty;
2678 my $leavesqty = $thisposition->leavesqty;
2679 my $client = $thisposition->client;
2680 my $symbol = $thisposition->symbol;
2681 my $side = $thisposition->side;
2682 my $endpoint = $thisposition->endpoint;
2683 my $origclient = $thisposition->origclient;
2684 my $prodmultiplier = $thisposition->prodmultiplier;
2685 my $xchangerate = $thisposition->xchangerate;
2686 my $account = $thisposition->account;
2687 my $clearcharge = $thisposition->clearcharge;
2688 my $exchangecharge = $thisposition->exchangecharge;
2689 my $liquiditycharge = $thisposition->liquiditycharge;
2690 my $seccharge = $thisposition->seccharge;
2691 my $nfacharge = $thisposition->nfacharge;
2692 #my $positiondate = $thisposition->positiondate;
2693
2694 # Write this line to a file
2695 #my $writestring = "$timestring,$positionid,$origid,$positionpx,$origqty,$leavesqty,$client,$symbol,$side,$endpoint,$origclient,$prodmultiplier,$xchangerate,$account,$clearcharge,$exchangecharge,$liquiditycharge,$seccharge,$nfacharge,$positiondate";
2696 my $writestring = "$timestring,$positionid,$origid,$positionpx,$origqty,$leavesqty,$client,$symbol,$side,$endpoint,$origclient,$prodmultiplier,$xchangerate,$account,$clearcharge,$exchangecharge,$liquiditycharge,$seccharge,$nfacharge";
2697 $writestring =~ s/^\s*(.*?)\s*$/$1/;
2698 print ARCHIVEFILE "$writestring\n";
2699 }
2700 }
2701}
2702PrintOut("Writing complete for $todaysfile!\n");
2703
2704# Close out the file
2705close ARCHIVEFILE;
2706PrintOut("==========================================\n");
2707
2708# If we don't have an existing ledger file, write one out
2709if(!$ledgerfilefound) {
2710 PrintOut("\n");
2711 PrintOut("\n");
2712 PrintOut("\n");
2713 PrintOut("\n");
2714 PrintOut("==========================================\n");
2715 PrintOut("Writing Ledger File!\n");
2716 WriteLedgerFile();
2717 PrintOut("Ledger file write complete!\n");
2718 PrintOut("==========================================\n");
2719 PrintOut("\n");
2720 PrintOut("\n");
2721 PrintOut("\n"); PrintOut("\n"); } ######################################################################## # Replenish all dividends --> We're going the full delete / replenish approach
2722# to avoid complications with dividend entries / timing
2723PrintOut("==========================================\n");
2724PrintOut("Beginning Dividend Sweep!\n");
2725PrintOut("==========================================\n");
2726
2727if($runmode eq "FullDayCalc") {
2728 # Delete all existing dividends from the pnlactual database
2729 my $div_del_str = "DELETE FROM pnlactual WHERE Client LIKE '%_div'";
2730 my $div_del_proc = $insdbh->prepare($div_del_str);
2731 $div_del_proc->execute;
2732
2733 my $div_str = "SELECT symbol,client,CONVERT(varchar,exdate,112) as exdate,amount FROM mod.pendingdividends ORDER BY exdate ASC";
2734 my $div_proc = $dbh->prepare($div_str);
2735 $div_proc->execute;
2736 my $divdata = $div_proc->fetchall_arrayref;
2737
2738 # Map for accumulation
2739 my %divmap = ();
2740
2741 PrintOut("Dividend Entries:\n");
2742 foreach my $row (@$divdata) {
2743 my $divclient = $row->[1];
2744 my $divdate = $row->[2];
2745 my $divamount = $row->[3];
2746 $divclient = $divclient . "_div";
2747
2748 # Add the dividend by client/symbol/date to pnlactual
2749 # This isn't exactly future proof, but assume that we only have one dividend entry per client per day
2750=check
2751 my $div_entry_str = "INSERT INTO pnlactual VALUES('$divdate','$divclient','$divamount')";
2752 print "$div_entry_str\n";
2753 my $div_entry_proc = $insdbh->prepare($div_entry_str);
2754 $div_entry_proc->execute;
2755=cut
2756
2757 # my %dividendsbyclientsymboldate = ();
2758 if(exists $divmap{$divclient} and defined $divmap{$divclient}{$divdate}) {
2759 my $existingpnl = $divmap{$divclient}{$divdate};
2760 $existingpnl = $existingpnl + $divamount;
2761 $divmap{$divclient}{$divdate} = $existingpnl;
2762 }
2763 else {
2764 $divmap{$divclient}{$divdate} = $divamount;
2765 }
2766
2767 # Print out if successful
2768 PrintOut("$divdate - $divclient - $divamount\n");
2769 }
2770
2771 # Iterate through divmap
2772 foreach my $divclient (sort keys %divmap) {
2773 my %divdatehashes = %{$divmap{$divclient}};
2774 foreach my $divdate (sort keys %divdatehashes) {
2775 my $divamount = $divmap{$divclient}{$divdate};
2776 my $div_entry_str = "INSERT INTO pnlactual VALUES('$divdate','$divclient','$divamount')";
2777 my $div_entry_proc = $insdbh->prepare($div_entry_str);
2778 $div_entry_proc->execute;
2779 }
2780 }
2781}
2782
2783PrintOut("==========================================\n");
2784PrintOut("Dividend Sweep Completed!\n");
2785PrintOut("==========================================\n");
2786########################################################################
2787
2788
2789# Indicate that we're finished
2790PrintOutStd("DAY ANALYSIS COMPLETED!\n");
2791
2792##########################################################################################################################################################################################
2793##########################################################################################################################################################################################
2794##########################################################################################################################################################################################
2795##########################################################################################################################################################################################
2796##########################################################################################################################################################################################
2797##########################################################################################################################################################################################
2798##########################################################################################################################################################################################
2799##########################################################################################################################################################################################
2800##########################################################################################################################################################################################
2801##########################################################################################################################################################################################
2802##########################################################################################################################################################################################
2803##########################################################################################################################################################################################
2804##########################################################################################################################################################################################
2805##########################################################################################################################################################################################
2806##########################################################################################################################################################################################
2807##########################################################################################################################################################################################
2808##########################################################################################################################################################################################
2809##########################################################################################################################################################################################
2810##########################################################################################################################################################################################
2811##########################################################################################################################################################################################
2812##########################################################################################################################################################################################
2813##########################################################################################################################################################################################
2814##########################################################################################################################################################################################
2815##########################################################################################################################################################################################
2816##########################################################################################################################################################################################
2817##########################################################################################################################################################################################
2818##########################################################################################################################################################################################
2819##########################################################################################################################################################################################
2820##########################################################################################################################################################################################
2821##########################################################################################################################################################################################
2822##########################################################################################################################################################################################
2823##########################################################################################################################################################################################
2824##########################################################################################################################################################################################
2825##########################################################################################################################################################################################
2826##########################################################################################################################################################################################
2827##########################################################################################################################################################################################
2828##########################################################################################################################################################################################
2829
2830# Used to print to out
2831sub PrintOut {
2832 my $printstr = $_[0];
2833 print PRINTERFILE $printstr;
2834}
2835
2836sub DebugPrintOut {
2837 if($debugmode) {
2838 my $printstr = $_[0];
2839 print PRINTERFILE $printstr;
2840 }
2841}
2842
2843sub PrintOutStd {
2844 my $printstr = $_[0];
2845 print PRINTERFILE $printstr;
2846 print $printstr;
2847}
2848
2849# Used to reset variables
2850sub ResetVars {
2851 $contraposreference = ();
2852 $sameposreference = ();
2853 $sameside = ();
2854 $contraside = ();
2855}
2856
2857# Quick buy side check
2858sub IsBuySide {
2859 my $sideparam = $_[0];
2860 if($sideparam eq "B") {
2861 return 1;
2862 }
2863}
2864
2865# Get Contra Side
2866sub GetContraSide {
2867 my $sideparam = $_[0];
2868 if($sideparam =~ "B") {
2869 return "S";
2870 }
2871 else {
2872 return "B";
2873 }
2874}
2875
2876# Used to print out the position maps
2877sub PrintPositionMap {
2878 my %mapref = %{$_[0]};
2879 foreach my $key (keys %mapref) {
2880 PrintOut("\t$key:\n");
2881 my %symbolhashes = %{$mapref{$key}};
2882 foreach my $symkey (keys %symbolhashes) {
2883 PrintOut("\t\t$symkey:\n\t\t\t");
2884 my @sympos = @{$symbolhashes{$symkey}};
2885 foreach (@sympos) {
2886 my $thisposition = $_;
2887 my $leavesamt = $thisposition->leavesqty;
2888 my $leavesprice = $thisposition->positionpx;
2889 my $leavesid = $thisposition->positionid;
2890 PrintOut("$leavesamt\@$leavesprice($leavesid)\n\t\t\t");
2891 }
2892 PrintOut("\n");
2893 }
2894 }
2895 PrintOut("\n");
2896}
2897
2898# Used to check for internal transactions
2899sub IsInternalCrossEndpoint {
2900 my $endpoint = $_[0];
2901 if(($endpoint eq "BFEX") || ($endpoint eq "EFPX")) {
2902 return 1;
2903 }
2904}
2905
2906# Used to see if an ID should be ignored
2907sub ShouldIgnoreID {
2908 my $id = $_[0];
2909 if(exists $ignoreids{$id}) {
2910 return 1;
2911 }
2912 return 0;
2913}
2914
2915# Check to see if we have a proper "Yes" or "No" response
2916sub IsValidYesNo {
2917 my $choice = $_[0];
2918 $choice =~ s/^\s+|\s+$//g;
2919 if(($choice ne "Y") && ($choice ne "N") && ($choice ne "yes") && ($choice ne "y") && ($choice ne "no") && ($choice ne "n")) {
2920 return 0;
2921 }
2922 return 1;
2923}
2924
2925# Returns 0 if "no", 1 if "yes"
2926sub GetYesNo {
2927 my $choice = $_[0];
2928 $choice =~ s/^\s+|\s+$//g;
2929 if(($choice eq "Y") || ($choice eq "Yes") || ($choice eq "yes") || ($choice eq "y")) {
2930 return 1;
2931 }
2932 return 0;
2933}
2934
2935# Check to see if an ID is in the qty mod map
2936sub IsIdInQtyModMap {
2937 my $id = $_[0];
2938 foreach my $checkid (keys %ledgerqtymodactions) {
2939 if($checkid eq $id) {
2940 return 1;
2941 }
2942 }
2943 return 0;
2944}
2945
2946# Prompt for user action for accounting ledger
2947sub PromptForUserAction {
2948 my $ledgerid = $_[0];
2949
2950 # Eliminating this part for now.
2951 ErrorAndShutdown("Encountered need for a ledger transaction for $ledgerid! This should no longer be necessary in the system and requires investigation! Performing a data dump and then exiting!\n");
2952 die;
2953
2954=comment
2955REPROMPTACTION:
2956 my $currentledgersize = @currentledgeractions;
2957 PrintOutStd("============================\n");
2958 PrintOutStd("LEDGER ACTION NEEDED for ID $ledgerid\n");
2959 PrintOutStd("============================\n");
2960 PrintOutStd("$currentledgersize actions in queue!\n");
2961 PrintOutStd("============================\n");
2962 PrintOutStd("What would you like to do?\n");
2963 PrintOutStd("1.) Modify $ledgerid quantity\n");
2964 PrintOutStd("2.) Modify quantity for other (future) IDs\n");
2965 PrintOutStd("3.) Add debt for client (to be resolved at the end of all fills)\n");
2966 PrintOutStd("4.) Ignore $ledgerid completely\n");
2967 PrintOutStd("5.) Ignore other IDs completely\n");
2968 PrintOutStd("6.) Add virtual BFEX transaction\n");
2969 PrintOutStd("8.) Clear all current ledger actions\n");
2970 PrintOutStd("E.) Enter direct ledger string\n");
2971 PrintOutStd("P.) Print current ledger actions\n");
2972 PrintOutStd("C.) Complete ledger actions\n");
2973 PrintOutStd("Choice: ");
2974
2975 my $choice = <STDIN>;
2976 $choice =~ s/^\s+|\s+$//g;
2977
2978 if($choice eq "1") {
2979 ChangeQuantityForCurrentID($ledgerid);
2980 }
2981 elsif($choice eq "2") {
2982 PromptChangeQuantityForID();
2983 }
2984 elsif($choice eq "3") {
2985 PromptForDebt();
2986 }
2987 elsif($choice eq "4") {
2988 PendIgnoreID($ledgerid);
2989 }
2990 elsif($choice eq "5") {
2991 PromptToIgnoreID();
2992 }
2993 elsif($choice eq "6") {
2994 PromptAddVirtualBFEX();
2995 }
2996 elsif($choice eq "8") {
2997 ClearLedgerActions();
2998 }
2999 elsif($choice eq "E") {
3000 PromptEnterDirectLedgerString();
3001 }
3002 elsif($choice eq "C") {
3003 # Verify ledger actions
3004 if($currentledgersize > 0) {
3005 PrintOutStd("Please confirm that you want to take the following ledger actions: \n");
3006 PrintOutLedgerActions();
3007
3008REPROMPTALLACTIONSYESNO:
3009 PrintOutStd("Take All Ledger Actions? (Y/N): ");
3010 my $takeactionchoices = <STDIN>;
3011 if(IsValidYesNo($takeactionchoices)) {
3012 if(GetYesNo($takeactionchoices)) {
3013 # Complete all ledger actions
3014 TakeAllLedgerActions();
3015 }
3016 else {
3017REPROMPTCANCELALLACTIONS:
3018 PrintOutStd("Are you sure you want to cancel all ledger transactions? (Y/N): ");
3019 my $areyousurecancel = <STDIN>;
3020 if(IsValidYesNo($areyousurecancel)){
3021 if(GetYesNo($areyousurecancel)) {
3022 goto REPROMPTACTION;
3023 }
3024 else {
3025 goto REPROMPTALLACTIONSYESNO;
3026 }
3027 }
3028 else {
3029 goto REPROMPTCANCELALLACTIONS;
3030 }
3031 }
3032 }
3033 else {
3034 PrintOutStd("Invalid choice entered! Please confirm whether or not you want to take the ledger actions!\n");
3035 goto REPROMPTALLACTIONSYESNO;
3036 }
3037 }
3038
3039 # All done. Complete the transaction.
3040 return;
3041 }
3042 elsif($choice eq "P") {
3043 PrintOutStd("\n");
3044 PrintOutStd("\n");
3045 PrintOutStd("\n");
3046 PrintOutLedgerActions();
3047 PrintOutStd("\n");
3048 PrintOutStd("\n");
3049 PrintOutStd("\n");
3050 }
3051 else {
3052 PrintOutStd("Invalid choice detected! Please try again!\n");
3053 goto REPROMPTACTION;
3054 }
3055
3056 # Go back to menu
3057 goto REPROMPTACTION;
3058=cut
3059}
3060
3061# Prompt for a direct ledger string to be entered
3062sub PromptEnterDirectLedgerString {
3063REPROMPTDIRECTSTRING:
3064 PrintOutStd("Please enter a direct string for the ledger (leave blank to cancel): ");
3065 my $ledgercommand = <STDIN>;
3066 $ledgercommand =~ s/^\s+|\s+$//g;
3067 if($ledgercommand eq "") {
3068 # Do nothing and return to the ledger menu
3069 return;
3070 }
3071 else {
3072REPROMPTDIRECTCONFIRM:
3073 # Confirm
3074 PrintOutStd("Are you sure you want to add \"$ledgercommand\" to the ledger queue? (Y/N): ");
3075 my $confirmdirectledgeradd = <STDIN>;
3076 if(!IsValidYesNo($confirmdirectledgeradd)) {
3077 PrintOutStd("Please enter Y or N!\n");
3078 goto REPROMPTDIRECTCONFIRM;
3079 }
3080 else {
3081 if(GetYesNo($confirmdirectledgeradd)) {
3082 push(@currentledgeractions, $ledgercommand);
3083 }
3084 else {
3085 PrintOutStd("User has cancelled direct addition of $ledgercommand!\n");
3086 goto REPROMPTDIRECTSTRING;
3087 }
3088 }
3089 }
3090}
3091
3092# Ignore an id
3093sub PromptToIgnoreID {
3094REPROMPTIGNORE:
3095 PrintOutStd("Which ID would you like to ignore completely (enter a blank for none)?: ");
3096 my $idchoice = <STDIN>;
3097 $idchoice =~ s/^\s+|\s+$//g;
3098 if($idchoice ne "") {
3099REPROMPTYESNOIGNORE:
3100 PrintOutStd("Are you sure you wish to ignore ID $idchoice? (Y/N): ");
3101 my $idconfirm = <STDIN>;
3102 if(!IsValidYesNo($idconfirm)) {
3103 PrintOutStd("Please enter Y or N!\n");
3104 goto REPROMPTYESNOIGNORE;
3105 }
3106 else {
3107 if(GetYesNo($idconfirm)) {
3108 PrintOutStd("Adding $idchoice to ignore list!\n");
3109 PendIgnoreID($idchoice);
3110 return;
3111 }
3112 else {
3113 PrintOutStd("Canceling ignoring of $idchoice!\n");
3114 goto REPROMPTIGNORE;
3115 }
3116 }
3117 }
3118 else {
3119 # Nope.
3120 return;
3121 }
3122}
3123
3124# Add a virtual transfer
3125sub PromptAddVirtualBFEX {
3126 # Prompt for all details
3127REPROMPTADDBFEX:
3128 PrintOutStd("What is the origination client for BFEX (blank to cancel)?: ");
3129 my $origclichoice = <STDIN>;
3130 $origclichoice =~ s/^\s+|\s+$//g;
3131 if($origclichoice eq "") {
3132 return;
3133 }
3134 PrintOutStd("What is the destination client for BFEX (blank to cancel)?: ");
3135 my $destclichoice = <STDIN>;
3136 $destclichoice =~ s/^\s+|\s+$//g;
3137 if($destclichoice eq "") {
3138 return;
3139 }
3140REPROMPTBFEXSYM:
3141 PrintOutStd("What symbol is this transaction for?: ");
3142 my $symbolchoice = <STDIN>;
3143 $symbolchoice =~ s/^\s+|\s+$//g;
3144 if($symbolchoice eq "") {
3145 PrintOutStd("Invalid symbol entered!\n");
3146 goto REPROMPTBFEXSYM;
3147 }
3148REPROMPTBFEXSIDE:
3149 PrintOutStd("What is the originating side of this BFEX (B/S)?: ");
3150 my $sidechoice = <STDIN>;
3151 $sidechoice =~ s/^\s+|\s+$//g;
3152 if(($sidechoice ne "B") && ($sidechoice ne "S")) {
3153 PrintOutStd("Invalid side entered! Please enter B or S!\n");
3154 goto REPROMPTBFEXSIDE;
3155 }
3156 my $contrasidechoice = GetContraSide($sidechoice);
3157 $contrasidechoice =~ s/^\s+|\s+$//g;
3158 PrintOutStd("How much should be transferred?: ");
3159 my $qtychoice = <STDIN>;
3160 $qtychoice =~ s/^\s+|\s+$//g;
3161 PrintOutStd("What price should be associated with this transfer?: ");
3162 my $pxchoice = <STDIN>;
3163 $pxchoice =~ s/^\s+|\s+$//g;
3164
3165 # Verify details
3166RECONFIRMBFEX:
3167 PrintOutStd("BFEX Transfer: $sidechoice $qtychoice $symbolchoice @ $pxchoice in $origclichoice, $contrasidechoice $qtychoice $symbolchoice @ $pxchoice $destclichoice\n");
3168 PrintOutStd("Is this correct? (Y/N): ");
3169 my $confirmbfex = <STDIN>;
3170 if(!IsValidYesNo($confirmbfex)) {
3171 PrintOutStd("Please enter Y or N!\n");
3172 goto RECONFIRMBFEX;
3173 }
3174 else {
3175 if(!GetYesNo($confirmbfex)) {
3176 PrintOutStd("Details are incorrect! Re-prompting user for input!\n");
3177 goto REPROMPTADDBFEX;
3178 }
3179 else {
3180 # Go ahead and add the BFEX
3181 push(@currentledgeractions, "ADDBFEX $sidechoice $qtychoice $symbolchoice $pxchoice $origclichoice $destclichoice");
3182 return;
3183 }
3184 }
3185}
3186
3187# Add an ID to the pending ignore list
3188sub PendIgnoreID {
3189 # Assign for ignoring
3190 my $id = $_[0];
3191 push(@currentledgeractions, "IGNORE $id");
3192}
3193
3194# Enter in a debt transaction
3195sub PromptForDebt {
3196 my @tempdebtqueue = ();
3197
3198REDEBTRESTART:
3199 PrintOutStd("==========================\n");
3200 PrintOutStd("ADD DEBT FOR CLIENT\n");
3201 PrintOutStd("==========================\n");
3202
3203REDEBTCLIENT:
3204 PrintOutStd("Which client would you like to enter debt for?: ");
3205 my $clientchoice = <STDIN>;
3206 $clientchoice =~ s/^\s+|\s+$//g;
3207 if($clientchoice eq "") {
3208 PrintOutStd("Please enter a valid client!\n");
3209 goto REDEBTCLIENT;
3210 }
3211
3212REDEBTSYMBOL:
3213 PrintOutStd("Which symbol would you like to enter debt for?: ");
3214 my $symbolchoice = <STDIN>;
3215 $symbolchoice =~ s/^\s+|\s+$//g;
3216 if($symbolchoice eq "") {
3217 PrintOutStd("Please enter a valid symbol!\n");
3218 goto REDEBTSYMBOL;
3219 }
3220
3221REDEBTSIDE:
3222 PrintOutStd("Which side would you like to enter this debt for (B/S)?: ");
3223 my $sidechoice = <STDIN>;
3224 $sidechoice=~ s/^\s+|\s+$//g;
3225 if(($sidechoice ne "B") && ($sidechoice ne "S")) {
3226 PrintOutStd("Invalid side of $sidechoice detected! Please choose either B or S!\n");
3227 goto REDEBTSIDE;
3228 }
3229
3230REDEBTAMOUNT:
3231 PrintOutStd("How much do you want to add to debt?: ");
3232 my $amountchoice = <STDIN>;
3233 $amountchoice =~ s/^\s+|\s+$//g;
3234 if($amountchoice <= 0) {
3235 PrintOutStd("Invalid amount of $amountchoice entered! Please enter a positive value!\n");
3236 goto REDEBTAMOUNT;
3237 }
3238
3239REDEBTDESTCLIENT:
3240 PrintOutStd("Which client should these positions eventually go into?: ");
3241 my $destclient = <STDIN>;
3242 $destclient =~ s/^\s+|\s+$//g;
3243 if($destclient eq "") {
3244 PrintOutStd("Invalid destination client entered! Please enter a valid client!\n");
3245 goto REDEBTDESTCLIENT;
3246 }
3247
3248 # Confirm that everything looks kosher
3249 PrintOutStd("=========================\n");
3250 PrintOutStd("Please verify details:\n");
3251 PrintOutStd("=========================\n");
3252 PrintOutStd("Debt originating client: $clientchoice\n");
3253 PrintOutStd("Symbol: $symbolchoice\n");
3254 PrintOutStd("Side: $sidechoice\n");
3255 PrintOutStd("Amount: $amountchoice\n");
3256 PrintOutStd("Destination client for this debt: $destclient\n");
3257
3258REDEBTCONFIRM:
3259 PrintOutStd("Are the entered details correct? (Y/N): ");
3260
3261 # Confirm the choices
3262 my $confirmchoices = <STDIN>;
3263 my $yesnoscan = GetYesNo($confirmchoices);
3264
3265 if(!IsValidYesNo($confirmchoices)) {
3266 PrintOutStd("Please enter Y or N!\n");
3267 goto REDEBTCONFIRM;
3268 }
3269 else {
3270 if(!GetYesNo($confirmchoices)) {
3271 PrintOutStd("Details are incorrect! Re-prompting user for input!\n");
3272 goto REDEBTRESTART;
3273 }
3274 }
3275
3276 # We should have all variables necessary for our debt.
3277 # Add this debt into the temp holder queue
3278 push(@tempdebtqueue, "DEBT $sidechoice $amountchoice $symbolchoice $clientchoice $destclient");
3279
3280 # Check to see if there are any more debts to be added.
3281READDMORECONFIRM:
3282 PrintOutStd("Would you like to add any more debts at this time? (Y/N): ");
3283 my $addmoredebtchoice = <STDIN>;
3284 if(!IsValidYesNo($addmoredebtchoice)) {
3285 PrintOutStd("Please enter Y or N!\n");
3286 goto READDMORECONFIRM;
3287 }
3288 else {
3289 if(GetYesNo($addmoredebtchoice)) {
3290 # Prompt again for debt
3291 goto REDEBTRESTART;
3292 }
3293 else {
3294 # Display what we have and confirm!
3295 PrintOutStd("============================\n");
3296 PrintOutStd("Debt Summary:\n");
3297 PrintOutStd("============================\n");
3298 foreach my $tempdebtstring (@tempdebtqueue) {
3299 PrintOutStd("$tempdebtstring\n");
3300 }
3301 PrintOutStd("\n");
3302
3303 # Confirm the debts in place.
3304RECONFIRMEXISTINGDEBTS:
3305 PrintOutStd("Are these debts correct? (Y/N): ");
3306 my $confirmdebtschoice = <STDIN>;
3307 if(IsValidYesNo($confirmdebtschoice)) {
3308 if(GetYesNo($confirmdebtschoice)) {
3309 # Don't clear the temp debt queue and return. Put actions into
3310 # the tempdebtqueue (as opposed to the temptempdebtqueue). Also,
3311 # note actions in the currentledgeractions.
3312 foreach my $tempdebtstring (@tempdebtqueue) {
3313 push(@currentledgeractions, $tempdebtstring);
3314 }
3315
3316 # Flush the temporary temporary debt queue
3317 @tempdebtqueue = ();
3318
3319 # Go back to the main menu
3320 return;
3321 }
3322 else {
3323 PrintOutStd("Debts are incorrect! Re-prompting for debts!\n");
3324 @tempdebtqueue = ();
3325 goto REDEBTRESTART;
3326 }
3327 }
3328 else {
3329 PrintOutStd("Invalid choice entered!\n");
3330 goto RECONFIRMEXISTINGDEBTS;
3331 }
3332 }
3333 }
3334}
3335
3336# Clear the ledger
3337sub ClearLedgerActions {
3338REPROMPTCLEARLEDGER:
3339 PrintOutStd("Are you sure you want to clear all current ledger actions? (Y/N): ");
3340 my $clearledgerchoice = <STDIN>;
3341 if(IsValidYesNo($clearledgerchoice)) {
3342 if(GetYesNo($clearledgerchoice)) {
3343 PrintOutStd("Clearing ledger actions!\n");
3344 @currentledgeractions = ();
3345 }
3346 else {
3347 # User has elected not to clear ledger
3348 PrintOutStd("User has elected not to clear ledger!\n");
3349 return;
3350 }
3351 }
3352 else {
3353 PrintOutStd("Invalid choice entered!\n");
3354 goto REPROMPTCLEARLEDGER;
3355 }
3356}
3357
3358# Print Out Ledger
3359sub PrintOutLedgerActions {
3360 my $currentactionsize = @currentledgeractions;
3361
3362 PrintOutStd("============================\n");
3363 PrintOutStd("CURRENT LEDGER ACTIONS\n");
3364 PrintOutStd("============================\n");
3365 if($currentactionsize > 0) {
3366 # Print out the short version for now
3367 foreach my $action (@currentledgeractions) {
3368 PrintOutStd("$action\n");
3369 }
3370 }
3371 else {
3372 PrintOutStd("No current actions in ledger!\n");
3373 }
3374 PrintOutStd("============================\n");
3375}
3376
3377# Iterate through the ledger and complete all pending actions. Then, flush the queue.
3378sub TakeAllLedgerActions {
3379 # Iterate through actions and complete them.
3380 foreach my $action (@currentledgeractions) {
3381 # Write this action into the ledger archive
3382 if(!$ledgerfilefound) {
3383 # Add this to the written ledger actions
3384 # print LEDGERWRITEFILE "$action\n";
3385 push(@ledgeractionstowrite, $action);
3386 }
3387 CompleteLedgerAction($action);
3388 }
3389
3390 # Flush the ledger
3391 @currentledgeractions = ();
3392}
3393
3394# Parse and complete ledger action
3395sub CompleteLedgerAction {
3396 # Take this action.
3397 my $action = $_[0];
3398
3399 # Spiit by space
3400 my @actionsplit = split " ", $action;
3401 my $baseaction = $actionsplit[0];
3402
3403 # We want to modify quantity for an order
3404 if($baseaction eq "QTYMOD") {
3405 ActionModifyQuantityForID($actionsplit[1], $actionsplit[2]);
3406 }
3407 elsif($baseaction eq "DEBT") {
3408 ActionGenerateDebtAsSpecified($actionsplit[1], $actionsplit[2], $actionsplit[3], $actionsplit[4], $actionsplit[5]);
3409 }
3410 elsif($baseaction eq "IGNORE") {
3411 ActionIgnoreID($actionsplit[1]);
3412 }
3413 elsif($baseaction eq "ADDBFEX") {
3414 ActionAddBFEX($action);
3415 }
3416 else {
3417 PrintOutStd("Invalid ledger action entered: $action! Doing nothing with this!\n");
3418 }
3419}
3420
3421# Modify quantity for an ID
3422sub ActionModifyQuantityForID {
3423 # Takes parameter with args of ID, and action
3424 my $id = $_[0];
3425 my $modquantity = $_[1];
3426
3427 PrintOutStd("LEDGER - Adding quantity modification for id $id to $modquantity!\n");
3428 $ledgerqtymodactions{$id} = $modquantity;
3429}
3430
3431# Generate debt as requested
3432sub ActionGenerateDebtAsSpecified {
3433 # Split this debt
3434 my $sidechoice = $_[0];
3435 my $amountchoice = $_[1];
3436 my $symbolchoice = $_[2];
3437 my $clientchoice = $_[3];
3438 my $destclient = $_[4];
3439
3440 PrintOutStd("LEDGER - Adding debt of $sidechoice $amountchoice $symbolchoice from $clientchoice to $destclient\n");
3441
3442 # Create a new debt position
3443 my $debtposition = new TradePosition;
3444 $debtposition->positionid("DEBTPOSID");
3445 $debtposition->origmsgid("DEBTPOSID");
3446 $debtposition->timestring("20990101-00:00:00:000");
3447 $debtposition->positionpx(0);
3448 $debtposition->origqty($amountchoice);
3449 $debtposition->leavesqty($amountchoice);
3450 $debtposition->client($destclient);
3451 $debtposition->account("UNWN");
3452 $debtposition->symbol($symbolchoice);
3453 $debtposition->side($sidechoice);
3454 $debtposition->endpoint("DEBT");
3455 $debtposition->prodmultiplier(1);
3456 $debtposition->xchangerate(1);
3457 $debtposition->origclient($clientchoice);
3458 $debtposition->clearcharge(0);
3459 $debtposition->exchangecharge(0);
3460 $debtposition->liquiditycharge(0);
3461 $debtposition->seccharge(0);
3462 $debtposition->nfacharge(0);
3463 $debtposition->bfexorigqtys(());
3464 $debtposition->bfexsizes(());
3465 $debtposition->bfexprices(());
3466 $debtposition->bfexposids(());
3467 $debtposition->bfexorigids(());
3468 $debtposition->bfexclearcharges(());
3469 $debtposition->bfexexchangecharges(());
3470 $debtposition->bfexliquiditycharges(());
3471 $debtposition->bfexseccharges(());
3472 $debtposition->bfexnfacharges(());
3473 $debtposition->bfexorigclients(());
3474 $debtposition->bfexxchangerates(());
3475 #$debtposition->bfexdates(());
3476 #$debtposition->positiondate("20990101");
3477
3478 # Push this into prod
3479 push(@debtqueue, $debtposition);
3480}
3481
3482# Ignore an ID
3483sub ActionIgnoreID {
3484 my $id = $_[0];
3485
3486 PrintOutStd("LEDGER - Adding command to ignore this ID: $id\n");
3487
3488 # Add this specified ID to the ignore list
3489 $ignoreids{$id} = 1;
3490}
3491
3492# Add BFEX transaction
3493sub ActionAddBFEX {
3494 # We can't formulate the BFEX at initiation, because it's made to be transacted at the end of the day. We have to just
3495 # queue up an action for now, and leave it at that.
3496 my $action = $_[0];
3497
3498 PrintOutStd("LEDGER - Adding BFEX $action into action queue!\n");
3499
3500 push(@bfexactions, $action);
3501}
3502
3503# Change quantity for a specific ID
3504sub ChangeQuantityForCurrentID {
3505 my $ledgerid = $_[0];
3506 $ledgerid =~ s/^\s+|\s+$//g;
3507
3508REPROMPTQTY:
3509 PrintOutStd("What should the quantity be set to for $ledgerid? (Please note that this will overwrite any other quantity assigned to this ID!): ");
3510 my $quantitychoice = <STDIN>;
3511 $quantitychoice =~ s/^\s+|\s+$//g;
3512 $_ = $quantitychoice;
3513 if (/^-?\d+$/) {
3514 # Issue a confirmation
3515REPROMPTCHANGEYESNO:
3516 PrintOutStd("Confirm: Change quantity for $ledgerid to $quantitychoice? (Y/N): ");
3517 my $yesnoconfirm = <STDIN>;
3518 if(IsValidYesNo($yesnoconfirm)) {
3519 if(GetYesNo($yesnoconfirm)) {
3520 # If confirmed, push it.
3521 push(@currentledgeractions, "QTYMOD $ledgerid $quantitychoice");
3522 }
3523 else {
3524 goto REPROMPTACTION;
3525 }
3526 }
3527 else {
3528 PrintOutStd("Invalid decision entered! Please enter Y/N!\n");
3529 goto REPROMPTCHANGEYESNO;
3530 }
3531 }
3532 else {
3533 PrintOutStd("Invalid quantity entered!\n");
3534 goto REPROMPTQTY;
3535 }
3536}
3537
3538
3539# Prompt for message ID
3540sub PromptChangeQuantityForID {
3541 PrintOutStd("What ID should we change the quantity for?: ");
3542 my $idchoice = <STDIN>;
3543 ChangeQuantityForCurrentID($idchoice);
3544}
3545
3546
3547# Get Total Position For Client and Symbol
3548sub GetTotalPositionForClientSymbol {
3549 my $clientparam = $_[0];
3550 my $symbolparam = $_[1];
3551
3552 # Counter variable
3553 my $totalposition = 0;
3554
3555 # Long positions
3556 if(exists $openlongpositionbyclientsymbol{$clientparam} and defined $openlongpositionbyclientsymbol{$clientparam}{$symbolparam}) {
3557 my @longposarr = @{$openlongpositionbyclientsymbol{$clientparam}{$symbolparam}};
3558 foreach my $longpos (@longposarr) {
3559 my $longqty = $longpos->leavesqty;
3560 $totalposition += $longqty;
3561 }
3562 }
3563
3564 # Short positions
3565 if(exists $openshortpositionbyclientsymbol{$clientparam} and defined $openshortpositionbyclientsymbol{$clientparam}{$symbolparam}) {
3566 my @shortposarr = @{$openshortpositionbyclientsymbol{$clientparam}{$symbolparam}};
3567 foreach my $shortpos (@shortposarr) {
3568 my $shortqty = $shortpos->leavesqty;
3569 $totalposition -= $shortqty;
3570 }
3571 }
3572
3573 return $totalposition;
3574}
3575
3576# Write out the ledger file if there are any ledger actions
3577sub WriteLedgerFile {
3578 my $ledgerwriteactionsize = @ledgeractionstowrite;
3579 if($ledgerwriteactionsize > 0) {
3580 # Iterate through and complete each of the actions
3581 my $ledgerwritefile = "/datlib/actualpnl/ledger." . $todaysymd . ".out";
3582 if($testwritemode) {
3583 $ledgerwritefile = "testledger." . $todaysymd . ".out";
3584 }
3585 open(LEDGERWRITEFILE, ">>", "$ledgerwritefile") || die "Failed to open ledger file write handle!\n";
3586 LEDGERWRITEFILE->autoflush;
3587
3588 foreach my $action (@ledgeractionstowrite) {
3589 print LEDGERWRITEFILE "$action\n";
3590 }
3591 }
3592}
3593
3594# Transact crosses for a client
3595sub TransactCrosses {
3596 my $posclient = $_[0];
3597 my $possymbol = $_[1];
3598 my $origclient = $_[2];
3599
3600 # Determine overall position
3601 my $totClientPos = GetTotalPositionForClientSymbol($posclient,$possymbol);
3602
3603 # Find our balance map. If our position is completely flat, it shouldn't matter where we're coming from.
3604 my $morepositionmapref;
3605 my $lesspositionmapref;
3606 if($totClientPos >= 0) {
3607 DebugPrintOut("Transaction cross: MOREPOSITIONMAPREF = longposmap, LESSPOSITIONMAPREF = shortposmap\n");
3608 $morepositionmapref = \%openlongpositionbyclientsymbol;
3609 $lesspositionmapref = \%openshortpositionbyclientsymbol;
3610 }
3611 else {
3612 DebugPrintOut("Transaction cross: MOREPOSITIONMAPREF = shortposmap, LESSPOSITIONMAPREF = longposmap\n");
3613 $morepositionmapref = \%openshortpositionbyclientsymbol;
3614 $lesspositionmapref = \%openlongpositionbyclientsymbol;
3615 }
3616
3617 # Consume all positions from the lesser map. If there are no positions, then we should already be done.
3618 if(exists $$lesspositionmapref{$posclient} and defined $$lesspositionmapref{$posclient}{$possymbol}) {
3619 my @lessposarr = @{$$lesspositionmapref{$posclient}{$possymbol}};
3620 my @moreposarr;
3621 if(exists $$morepositionmapref{$posclient} and defined $$morepositionmapref{$posclient}{$possymbol}) {
3622 @moreposarr = @{$$morepositionmapref{$posclient}{$possymbol}};
3623 }
3624 else {
3625 PrintOutStd("ERROR: WHEN ATTEMPTING TO TRANSACT CROSSES FOR $posclient:$possymbol, THE POSITION MAP FOR THE CLIENT'S GREATER POSITION COULD NOT BE FOUND! EXITING!\n");
3626 #die("ERROR: WHEN ATTEMPTING TO TRANSACT CROSSES FOR $posclient:$possymbol, THE POSITION MAP FOR THE CLIENT'S GREATER POSITION COULD NOT BE FOUND! EXITING!\n");
3627 ErrorAndShutdown("ERROR: WHEN ATTEMPTING TO TRANSACT CROSSES FOR $posclient:$possymbol, THE POSITION MAP FOR THE CLIENT'S GREATER POSITION COULD NOT BE FOUND! EXITING!\n");
3628 }
3629
3630 my $lesspossize = @lessposarr;
3631 my $morepossize = @moreposarr;
3632 PrintOut("Transacting available position crosses for $posclient:$possymbol for a position of $totClientPos. We have $lesspossize positions in our lesser position side, and $morepossize in our greater position side!\n");
3633
3634 foreach my $lesspos (@lessposarr) {
3635 # Pull off a position from the lesser position array.
3636 my $lessposorigqty = $lesspos->origqty;
3637 my $lessposleaves = $lesspos->leavesqty;
3638 my $lesspospx = $lesspos->positionpx;
3639 my $lesspxmult = $lesspos->prodmultiplier;
3640 my $lessposxchangerate = $lesspos->xchangerate;
3641 my $lessposendpoint = $lesspos->endpoint;
3642 my $lessposposid = $lesspos->positionid;
3643 my $lessposorigid = $lesspos->origmsgid;
3644 my $lessposclearcharge = $lesspos->clearcharge;
3645 my $lessposexchangecharge = $lesspos->exchangecharge;
3646 my $lessposliquiditycharge = $lesspos->liquiditycharge;
3647 my $lessposseccharge = $lesspos->seccharge;
3648 my $lessposnfacharge = $lesspos->nfacharge;
3649
3650 DebugPrintOut("Initiating lesser crossing transaction of size $lessposleaves!\n");
3651
3652 while($lessposleaves > 0) {
3653 my $morepos = shift(@moreposarr);
3654 my $moreposorigqty = $morepos->origqty;
3655 my $moreposleaves = $morepos->leavesqty;
3656 my $morepospx = $morepos->positionpx;
3657 my $moreposxchangerate = $morepos->xchangerate;
3658 my $moreposposid = $morepos->positionid;
3659 my $moreposorigid = $morepos->origmsgid;
3660 my $moreposaccount = $morepos->account;
3661 my $moreposendpoint = $morepos->endpoint;
3662 my $moreposclearcharge = $morepos->clearcharge;
3663 my $moreposexchangecharge = $morepos->exchangecharge;
3664 my $moreposliquiditycharge = $morepos->liquiditycharge;
3665 my $moreposseccharge = $morepos->seccharge;
3666 my $moreposnfacharge = $morepos->nfacharge;
3667
3668 # Total up the fees
3669 my $totalfeecharge = 0;
3670
3671 DebugPrintOut("Countering with greater transaction of size $moreposleaves!\n");
3672
3673 my $transactamount;
3674 if($moreposleaves >= $lessposleaves) {
3675 # We have enough to eliminate the lesser position. Calculate closed PNL based on the lesser position
3676 # and move on to the next fill.
3677 $transactamount = $lessposleaves;
3678
3679 # If we still have size left in this position, make sure to put it back for the next position
3680 $moreposleaves -= $lessposleaves;
3681
3682 if($moreposleaves > 0) {
3683 $morepos->leavesqty($moreposleaves);
3684 unshift(@moreposarr, $morepos);
3685 }
3686
3687 # Determine which side the fees should be proportioned on
3688 my $lessfeeratiomult = $lessposleaves / $lessposorigqty;
3689 my $lessposclearhold = $lessposclearcharge * $lessfeeratiomult;
3690 my $lessposexchangehold = $lessposexchangecharge * $lessfeeratiomult;
3691 my $lessposliquidityhold = $lessposliquiditycharge * $lessfeeratiomult;
3692 my $lesspossechold = $lessposseccharge * $lessfeeratiomult;
3693 my $lessposnfahold = $lessposnfacharge * $lessfeeratiomult;
3694 if(ShouldConvertFeeEndpoint($lessposendpoint)) {
3695 #$lessposclearhold = $lessposclearhold / $lessposxchangerate;
3696 $lessposexchangehold = $lessposexchangehold / $lessposxchangerate;
3697 $lessposliquidityhold = $lessposliquidityhold / $lessposxchangerate;
3698 $lesspossechold = $lesspossechold / $lessposxchangerate;
3699 $lessposnfahold = $lessposnfahold / $lessposxchangerate;
3700 }
3701 my $totallessposcharge = $lessposclearhold + $lessposexchangehold + $lessposliquidityhold + $lesspossechold + $lessposnfahold;
3702
3703 my $morefeeratiomult = $lessposleaves / $moreposorigqty;
3704 $moreposclearcharge = $moreposclearcharge * $morefeeratiomult;
3705 $moreposexchangecharge = $moreposexchangecharge * $morefeeratiomult;
3706 $moreposliquiditycharge = $moreposliquiditycharge * $morefeeratiomult;
3707 $moreposseccharge = $moreposseccharge * $morefeeratiomult;
3708 $moreposnfacharge = $moreposnfacharge * $morefeeratiomult;
3709 if(ShouldConvertFeeEndpoint($moreposendpoint)) {
3710 #$moreposclearcharge = $moreposclearcharge / $moreposxchangerate;
3711 $moreposexchangecharge = $moreposexchangecharge / $moreposxchangerate;
3712 $moreposliquiditycharge = $moreposliquiditycharge / $moreposxchangerate;
3713 $moreposseccharge = $moreposseccharge / $moreposxchangerate;
3714 $moreposnfacharge = $moreposnfacharge / $moreposxchangerate;
3715 }
3716 my $totalmoreposcharge = $moreposclearcharge + $moreposexchangecharge + $moreposliquiditycharge + $moreposseccharge + $moreposnfacharge;
3717
3718 # Create the fee
3719 $totalfeecharge += $totallessposcharge + $totalmoreposcharge;
3720
3721 if($realtimemode) {
3722 # Insert fees on the day
3723 my $totalclearcharge = $lessposclearhold + $moreposclearcharge;
3724 my $totalexchangecharge = $lessposexchangehold + $moreposexchangecharge;
3725 my $totalliquiditycharge = $lessposliquidityhold + $moreposliquiditycharge;
3726 my $totalseccharge = $lesspossechold + $moreposseccharge;
3727 my $totalnfacharge = $lessposnfahold + $moreposnfacharge;
3728 InsertAmountToCASEMap(\%caseclearfeepnl, $origclient, $moreposaccount, $possymbol, $moreposendpoint, $totalclearcharge);
3729 InsertAmountToCASEMap(\%caseexfeepnl, $origclient, $moreposaccount, $possymbol, $moreposendpoint, $totalexchangecharge);
3730 InsertAmountToCASEMap(\%caseliqfeepnl, $origclient, $moreposaccount, $possymbol, $moreposendpoint, $totalliquiditycharge);
3731 InsertAmountToCASEMap(\%casesecfeepnl, $origclient, $moreposaccount, $possymbol, $moreposendpoint, $totalseccharge);
3732 InsertAmountToCASEMap(\%casenfafeepnl, $origclient, $moreposaccount, $possymbol, $moreposendpoint, $totalnfacharge);
3733 }
3734
3735 # Insert the fee into a map
3736 InsertFeeForClientSymbol($totalfeecharge, $origclient, $possymbol);
3737
3738 DebugPrintOut("Total Fee Charge IIIa is: $totalfeecharge, generated from first ratio of ($lessposleaves / $lessposorigqty) for $totallessposcharge. Second ratio is ($lessposleaves / $moreposorigqty), for $totalmoreposcharge.\n");
3739 }
3740 else {
3741 # We don't have enough to eliminate the lesser position. Calculate closed PNL based on the extracted
3742 # position and move on the next fill.
3743 $transactamount = $moreposleaves;
3744
3745 my $lessfeeratiomult = $moreposleaves / $lessposorigqty;
3746 my $lessposclearhold = $lessposclearcharge * $lessfeeratiomult;
3747 my $lessposexchangehold = $lessposexchangecharge * $lessfeeratiomult;
3748 my $lessposliquidityhold = $lessposliquiditycharge * $lessfeeratiomult;
3749 my $lesspossechold = $lessposseccharge * $lessfeeratiomult;
3750 my $lessposnfahold = $lessposnfacharge * $lessfeeratiomult;
3751 if(ShouldConvertFeeEndpoint($lessposendpoint)) {
3752 #$lessposclearhold = $lessposclearhold / $lessposxchangerate;
3753 $lessposexchangehold = $lessposexchangehold / $lessposxchangerate;
3754 $lessposliquidityhold = $lessposliquidityhold / $lessposxchangerate;
3755 $lesspossechold = $lesspossechold / $lessposxchangerate;
3756 $lessposnfahold = $lessposnfahold / $lessposxchangerate;
3757 }
3758 my $totallessposcharge = $lessposclearhold + $lessposexchangehold + $lessposliquidityhold + $lesspossechold + $lessposnfahold;
3759
3760 my $feeratiomult = $moreposleaves / $moreposorigqty;
3761 $moreposclearcharge = $moreposclearcharge * $feeratiomult;
3762 $moreposexchangecharge = $moreposexchangecharge * $feeratiomult;
3763 $moreposliquiditycharge = $moreposliquiditycharge * $feeratiomult;
3764 $moreposseccharge = $moreposseccharge * $feeratiomult;
3765 $moreposnfacharge = $moreposnfacharge * $feeratiomult;
3766 if(ShouldConvertFeeEndpoint($moreposendpoint)) {
3767 #$moreposclearcharge = $moreposclearcharge / $moreposxchangerate;
3768 $moreposexchangecharge = $moreposexchangecharge / $moreposxchangerate;
3769 $moreposliquiditycharge = $moreposliquiditycharge / $moreposxchangerate;
3770 $moreposseccharge = $moreposseccharge / $moreposxchangerate;
3771 $moreposnfacharge = $moreposnfacharge / $moreposxchangerate;
3772 }
3773 my $totalmoreposcharge = $moreposclearcharge + $moreposexchangecharge + $moreposliquiditycharge + $moreposseccharge + $moreposnfacharge;
3774
3775 # Create the fee
3776 $totalfeecharge += $totallessposcharge + $totalmoreposcharge;
3777
3778 if($realtimemode) {
3779 # Insert fees on the day
3780 my $totalclearcharge = $lessposclearhold + $moreposclearcharge;
3781 my $totalexchangecharge = $lessposexchangehold + $moreposexchangecharge;
3782 my $totalliquiditycharge = $lessposliquidityhold + $moreposliquiditycharge;
3783 my $totalseccharge = $lesspossechold + $moreposseccharge;
3784 my $totalnfacharge = $lessposnfahold + $moreposnfacharge;
3785 InsertAmountToCASEMap(\%caseclearfeepnl, $origclient, $moreposaccount, $possymbol, $moreposendpoint, $totalclearcharge);
3786 InsertAmountToCASEMap(\%caseexfeepnl, $origclient, $moreposaccount, $possymbol, $moreposendpoint, $totalexchangecharge);
3787 InsertAmountToCASEMap(\%caseliqfeepnl, $origclient, $moreposaccount, $possymbol, $moreposendpoint, $totalliquiditycharge);
3788 InsertAmountToCASEMap(\%casesecfeepnl, $origclient, $moreposaccount, $possymbol, $moreposendpoint, $totalseccharge);
3789 InsertAmountToCASEMap(\%casenfafeepnl, $origclient, $moreposaccount, $possymbol, $moreposendpoint, $totalnfacharge);
3790 }
3791
3792 # Insert the fee into a map
3793 InsertFeeForClientSymbol($totalfeecharge, $origclient, $possymbol);
3794
3795
3796 DebugPrintOut("Total Fee Charge IIIb is: $totalfeecharge, generated from first ratio of ($moreposleaves / $lessposorigqty) for $totallessposcharge. Second ratio is ($moreposleaves / $moreposorigqty), for $totalmoreposcharge.\n");
3797 }
3798
3799 DebugPrintOut("Cross transaction amount is $transactamount, and size left to counter at this point is $lessposleaves!\n");
3800
3801 # Calculate PNL and close the transaction.
3802 my $moreposissell = (\%openshortpositionbyclientsymbol == $lesspositionmapref);
3803 my $closedpnl = $transactamount * (($moreposissell) ? ($morepospx - $lesspospx) : ($lesspospx - $morepospx)) * $lesspxmult / $lessposxchangerate + $totalfeecharge;
3804
3805 if($realtimemode) {
3806 # Insert fees on the day
3807 my $closedpnlwithoutfees = $closedpnl - $totalfeecharge;
3808 InsertAmountToCASEMap(\%casedaypnl, $origclient, $moreposaccount, $possymbol, $moreposendpoint, $closedpnlwithoutfees);
3809 }
3810
3811 if(exists $closedpnlbyclientsymbol{$origclient} and defined $closedpnlbyclientsymbol{$origclient}{$possymbol}) {
3812 my $existingpnl = $closedpnlbyclientsymbol{$origclient}{$possymbol};
3813 $existingpnl = $existingpnl + $closedpnl;
3814 $closedpnlbyclientsymbol{$origclient}{$possymbol} = $existingpnl;
3815 }
3816 else {
3817 $closedpnlbyclientsymbol{$origclient}{$possymbol} = $closedpnl;
3818 }
3819
3820 my $moreposside;
3821 my $lessposside;
3822 if($moreposissell) {
3823 $moreposside = "S";
3824 $lessposside = "B";
3825 }
3826 else {
3827 $moreposside = "B";
3828 $lessposside = "S";
3829 }
3830
3831 my $storedpnlnumber = $closedpnlbyclientsymbol{$origclient}{$possymbol};
3832 PrintOut("CCONTRA: P&L: ($origclient:$possymbol:$closedpnl:$storedpnlnumber) -- ($moreposside/$lessposside) $transactamount $possymbol @ ($morepospx/$lesspospx) ($moreposposid/$lessposposid)\n");
3833
3834 # Update the amount that we still have to cover.
3835 $lessposleaves -= $transactamount;
3836
3837 DebugPrintOut("Size left to counter is $lessposleaves after single transaction!\n");
3838 }
3839 }
3840
3841 # Wipe the lesser pos array, as we should have emptied it at this point.
3842 @lessposarr = ();
3843
3844 # Put the maps back into place
3845 $$lesspositionmapref{$posclient}{$possymbol} = \@lessposarr;
3846 $$morepositionmapref{$posclient}{$possymbol} = \@moreposarr;
3847 }
3848}
3849
3850# Insert Fee for Client / Symbol Pair
3851sub InsertFeeForClientSymbol {
3852 my $feetoadd = $_[0];
3853 my $feeclient = $_[1];
3854 my $feesymbol = $_[2];
3855
3856 if(exists $totalfeebyclientsymbol{$feeclient} and defined $totalfeebyclientsymbol{$feeclient}{$feesymbol}) {
3857 my $existingfee = $totalfeebyclientsymbol{$feeclient}{$feesymbol};
3858 $existingfee = $existingfee + $feetoadd;
3859 $totalfeebyclientsymbol{$feeclient}{$feesymbol} = $existingfee;
3860 }
3861 else {
3862 $totalfeebyclientsymbol{$feeclient}{$feesymbol} = $feetoadd;
3863 }
3864}
3865
3866# Generate the Marks MapGe
3867sub GenerateMarksMap {
3868 my $quotesfile = "/datlib/quote2.csv";
3869 open(QUOTEFILEFORREAD, "$quotesfile") || die "Could not open quotes for real time read!\n";
3870 QUOTEFILEFORREAD->autoflush;
3871 while(<QUOTEFILEFORREAD>) {
3872 my $quoteline = $_;
3873 my @fields = split ",", $quoteline;
3874 my $fieldcount = @fields;
3875 if($fieldcount == 4) {
3876 my $quotesymbolendpoint = $fields[0];
3877 my @quotesymepsplit = split ":", $quotesymbolendpoint;
3878 my $quotesymbol = $quotesymepsplit[0];
3879 my $quotebid = $fields[1];
3880 my $quoteoffer = $fields[2];
3881 my $quoteprint = $fields[3];
3882 my $quotemark;
3883 if(($quotebid ne "NaN") && ($quoteoffer ne "NaN")) {
3884 $quotemark = ($quotebid + $quoteoffer) / 2;
3885 $quotemark =~ s/^\s+|\s+$//g;
3886 $marksmap{$quotesymbol} = $quotemark;
3887 }
3888 elsif($quoteprint ne "NaN\n") {
3889 $quotemark = $quoteprint;
3890 $quotemark =~ s/^\s+|\s+$//g;
3891 $marksmap{$quotesymbol} = $quotemark;
3892 }
3893 }
3894 }
3895}
3896
3897# Insert amount to CASE map
3898sub InsertAmountToCASEMap {
3899 my $casemapref = $_[0];
3900 my %casemap = %{$casemapref};
3901 my $caseclient = $_[1];
3902 my $caseaccount = $_[2];
3903 my $casesymbol = $_[3];
3904 my $caseendpoint = $_[4];
3905 my $caseamount = $_[5];
3906 $caseclient =~ s/^\s+|\s+$//g;
3907 $caseaccount =~ s/^\s+|\s+$//g;
3908 $casesymbol =~ s/^\s+|\s+$//g;
3909 $caseendpoint =~ s/^\s+|\s+$//g;
3910
3911 if(!$caseamount) {
3912 return;
3913 }
3914
3915 # If we already have an amount there, sum it up
3916 if($$casemapref{$caseclient}{$caseaccount}{$casesymbol}{$caseendpoint}) {
3917 my $existingamount = $casemap{$caseclient}{$caseaccount}{$casesymbol}{$caseendpoint};
3918 $caseamount = $caseamount + $existingamount;
3919 }
3920 $$casemapref{$caseclient}{$caseaccount}{$casesymbol}{$caseendpoint} = $caseamount;
3921}
3922
3923
3924# Generate the real time numbers
3925sub GenerateRealTimePNLFile {
3926 # Re-Generate the CASE Position PNL Map
3927 RegenerateCasePosPNL();
3928 GenerateCASESets();
3929
3930 # Generate Time
3931 #my $currtime = time;
3932 #my $fulltime = strftime "%H:%M:%S", localtime $currtime;
3933 #$fulltime .= sprintf ".%03d", ($currtime - int($currtime)) * 1000;
3934 my $fulltime = int (gettimeofday * 1000 );
3935
3936 # Generate the Real Time PNL Lines
3937 my @rtpnlfilelines = ();
3938 foreach my $clientkey (keys %caseiterationmap) {
3939 my %clientmap = %{$caseiterationmap{$clientkey}};
3940 foreach my $accountkey (keys %clientmap) {
3941 my %accountmap = %{$clientmap{$accountkey}};
3942 foreach my $symbolkey (keys %accountmap) {
3943 my %symbolmap = %{$accountmap{$symbolkey}};
3944 foreach my $endpointkey (keys %symbolmap) {
3945 # Direct Injections
3946 my $daypnlnum = $casedaypnl{$clientkey}{$accountkey}{$symbolkey}{$endpointkey};
3947 my $clearfeepnlnum = $caseclearfeepnl{$clientkey}{$accountkey}{$symbolkey}{$endpointkey};
3948 my $exfeepnlnum = $caseexfeepnl{$clientkey}{$accountkey}{$symbolkey}{$endpointkey};
3949 my $liqfeepnlnum = $caseliqfeepnl{$clientkey}{$accountkey}{$symbolkey}{$endpointkey};
3950 my $secfeepnlnum = $casesecfeepnl{$clientkey}{$accountkey}{$symbolkey}{$endpointkey};
3951 my $nfafeepnlnum = $casenfafeepnl{$clientkey}{$accountkey}{$symbolkey}{$endpointkey};
3952
3953 # Calculated Injections
3954 my $pospnlnum = $casepositionpnl{$clientkey}{$accountkey}{$symbolkey}{$endpointkey};
3955
3956 # Compensators
3957 if(!$daypnlnum) {
3958 $daypnlnum = 0;
3959 }
3960 if(!$clearfeepnlnum) {
3961 $clearfeepnlnum = 0;
3962 }
3963 if(!$exfeepnlnum) {
3964 $exfeepnlnum = 0;
3965 }
3966 if(!$liqfeepnlnum) {
3967 $liqfeepnlnum = 0;
3968 }
3969 if(!$secfeepnlnum) {
3970 $secfeepnlnum = 0;
3971 }
3972 if(!$nfafeepnlnum) {
3973 $nfafeepnlnum = 0;
3974 }
3975 if(!$pospnlnum) {
3976 $pospnlnum = 0;
3977 }
3978
3979 # Big Kahuna
3980 my $totalnetpnlnum = $pospnlnum + $daypnlnum + $clearfeepnlnum + $exfeepnlnum + $liqfeepnlnum + $nfafeepnlnum + $secfeepnlnum;
3981
3982 # Generate the PNL Line
3983 my $pnlline = "$fulltime:$accountkey:$clientkey:$symbolkey:$endpointkey:$pospnlnum:$daypnlnum:$totalnetpnlnum:$clearfeepnlnum:$exfeepnlnum:$liqfeepnlnum:$secfeepnlnum:$nfafeepnlnum\n";
3984 #print "DEBUG: PNL LINE: $pnlline";
3985 push(@rtpnlfilelines, $pnlline);
3986 }
3987 }
3988 }
3989 }
3990
3991 # DEBUG: Print out summaries
3992 # Position Position
3993 if($realtimemode) {
3994 PrintOut("====================================\n");
3995 my $totalpositionpnl = GetTotalFromCASEMap(\%casepositionpnl);
3996 my $totalclearfeepnl = GetTotalFromCASEMap(\%caseclearfeepnl);
3997 my $totalexfeepnl = GetTotalFromCASEMap(\%caseexfeepnl);
3998 my $totalliqfeepnl = GetTotalFromCASEMap(\%caseliqfeepnl);
3999 my $totalsecfeepnl = GetTotalFromCASEMap(\%casesecfeepnl);
4000 my $totalnfafeepnl = GetTotalFromCASEMap(\%casenfafeepnl);
4001 my $totalfeepnl = $totalclearfeepnl + $totalexfeepnl + $totalliqfeepnl + $totalsecfeepnl + $totalnfafeepnl;
4002 my $totaldaypnl = GetTotalFromCASEMap(\%casedaypnl);
4003 my $totalnetpnl = $totaldaypnl + $totalfeepnl + $totalpositionpnl;
4004 PrintOut("Total Position PNL: $totalpositionpnl\n");
4005 PrintOut("Total Fee PNL: $totalfeepnl\n");
4006 PrintOut("Total Day PNL: $totaldaypnl\n");
4007 PrintOut("Total Net PNL: $totalnetpnl\n");
4008 PrintOut("====================================\n");
4009 }
4010
4011 # We have all of our file lines.
4012 # Write the new file!
4013 open(RTFILEWRITE, ">", "$rtpnlwritefile") || die "Could not open real time pnl file for writing!";
4014 RTFILEWRITE->autoflush;
4015 foreach my $writeline (@rtpnlfilelines) {
4016 print RTFILEWRITE $writeline;
4017 }
4018 close RTFILEWRITE;
4019}
4020
4021# Generate which CASE sets we have to go through
4022sub GenerateCASESets {
4023 %caseiterationmap = ();
4024 AddMapCASEPairs(\%casedaypnl);
4025 AddMapCASEPairs(\%caseclearfeepnl);
4026 AddMapCASEPairs(\%caseexfeepnl);
4027 AddMapCASEPairs(\%caseliqfeepnl);
4028 AddMapCASEPairs(\%casesecfeepnl);
4029 AddMapCASEPairs(\%casenfafeepnl);
4030 AddMapCASEPairs(\%casepositionpnl);
4031}
4032
4033# Add CASE pairs from an individual map
4034sub AddMapCASEPairs {
4035 my $casemapref = $_[0];
4036 my %casemapfull = %$casemapref;
4037 my $totalamount = 0;
4038 foreach my $clientkey (keys %casemapfull) {
4039 my %accounthash = %{$casemapfull{$clientkey}};
4040 foreach my $accountkey (keys %accounthash) {
4041 my %symbolhash = %{$casemapfull{$clientkey}{$accountkey}};
4042 foreach my $symbolkey (keys %symbolhash) {
4043 my %endpointhash = %{$casemapfull{$clientkey}{$accountkey}{$symbolkey}};
4044 foreach my $endpointkey (keys %endpointhash) {
4045 $caseiterationmap{$clientkey}{$accountkey}{$symbolkey}{$endpointkey} = 1;
4046 }
4047 }
4048 }
4049 }
4050}
4051
4052# Generate the position PNL by client,account,symbol,endpoint
4053sub RegenerateCasePosPNL {
4054 %casepositionpnl = ();
4055
4056 # Iterate over our existing open position maps and mark to market.
4057 # First, check our long position map.
4058 foreach my $clientkey (keys %openlongpositionbyclientsymbol) {
4059 my %longsymbolmap = %{$openlongpositionbyclientsymbol{$clientkey}};
4060 foreach my $symbolkey (keys %longsymbolmap) {
4061 my @longsympositions = @{$longsymbolmap{$symbolkey}};
4062 foreach my $longposition (@longsympositions) {
4063 my $longleaves = $longposition->leavesqty;
4064 my $longpx = $longposition->positionpx;
4065 my $longmultiplier = $longposition->prodmultiplier;
4066 my $longxchangerate = $longposition->xchangerate;
4067 my $longaccount = $longposition->account;
4068 my $longendpoint = $longposition->endpoint;
4069 my $longorigclient = $longposition->origclient;
4070
4071 # Get the existing mark. If we don't have one, mark
4072 # to the existing position, which should generate 0 PNL.
4073 my $symbolmark = $marksmap{$symbolkey};
4074 if(!$symbolmark) {
4075 $symbolmark = $longpx;
4076 }
4077
4078 # Calculate the PNL for this position and insert it into the map.
4079 # Make sure to do the position PNL only, and not include any fees.
4080 my $longpnlcalc = $longleaves * ($symbolmark - $longpx) * $longmultiplier / $longxchangerate;
4081 if(!IsInternalCrossEndpoint($longendpoint)) {
4082 InsertAmountToCASEMap(\%casepositionpnl, $longorigclient, $longaccount, $symbolkey, $longendpoint, $longpnlcalc);
4083 }
4084 }
4085 }
4086 }
4087
4088 # Next, check our short position map
4089 foreach my $clientkey (keys %openshortpositionbyclientsymbol) {
4090 my %shortsymbolmap = %{$openshortpositionbyclientsymbol{$clientkey}};
4091 foreach my $symbolkey (keys %shortsymbolmap) {
4092 my @shortsympositions = @{$shortsymbolmap{$symbolkey}};
4093 foreach my $shortposition (@shortsympositions) {
4094 my $shortleaves = $shortposition->leavesqty;
4095 my $shortpx = $shortposition->positionpx;
4096 my $shortmultiplier = $shortposition->prodmultiplier;
4097 my $shortxchangerate = $shortposition->xchangerate;
4098 my $shortaccount = $shortposition->account;
4099 my $shortendpoint = $shortposition->endpoint;
4100 my $shortorigclient = $shortposition->origclient;
4101
4102 # Get the existing mark. If we don't have one, mark
4103 # to the existing position, which should generate 0 PNL.
4104 my $symbolmark = $marksmap{$symbolkey};
4105 if(!$symbolmark) {
4106 $symbolmark = $shortpx;
4107 }
4108
4109 # Calculate the PNL for this position and insert it into the map.
4110 # Make sure to do the position PNL only, and not include any fees.
4111 my $shortpnlcalc = $shortleaves * ($shortpx - $symbolmark) * $shortmultiplier / $shortxchangerate;
4112 if(!IsInternalCrossEndpoint($shortendpoint)) {
4113 InsertAmountToCASEMap(\%casepositionpnl, $shortorigclient, $shortaccount, $symbolkey, $shortendpoint, $shortpnlcalc);
4114 }
4115 }
4116 }
4117 }
4118}
4119
4120
4121# Get total value from a CASE Map
4122sub GetTotalFromCASEMap {
4123 my $casemapref = $_[0];
4124 my %casemapfull = %$casemapref;
4125 my $totalamount = 0;
4126 foreach my $clientkey (keys %casemapfull) {
4127 my %accounthash = %{$casemapfull{$clientkey}};
4128 foreach my $accountkey (keys %accounthash) {
4129 my %symbolhash = %{$casemapfull{$clientkey}{$accountkey}};
4130 foreach my $symbolkey (keys %symbolhash) {
4131 my %endpointhash = %{$casemapfull{$clientkey}{$accountkey}{$symbolkey}};
4132 foreach my $endpointkey (keys %endpointhash) {
4133 my $value = $casemapfull{$clientkey}{$accountkey}{$symbolkey}{$endpointkey};
4134 $totalamount = $totalamount + $value;
4135 }
4136 }
4137 }
4138 }
4139
4140 return $totalamount;
4141}
4142
4143# Determine whether or not this is a fee conversion endpoint
4144sub ShouldConvertFeeEndpoint {
4145 my $endpointtocheck = $_[0];
4146 if(($endpointtocheck eq "EURX") or ($endpointtocheck eq "BMNF") or ($endpointtocheck eq "BVSP")) {
4147 return 1;
4148 }
4149 return 0;
4150}
4151
4152# Throw an error email if Actual PNL is crashing
4153sub ErrorAndShutdown {
4154 my $errorstring = $_[0];
4155 my $finalerrorstring = "Actual PNL System Error and Shutdown. Contact Trade Support for investigation: " . "\n" . $errorstring;
4156 my $mailaddress;
4157 $mailaddress = "tradesupport\@bluefirecap.com";
4158 if($testwritemode) {
4159 $mailaddress = "iwilke\@bluefirecap.com";
4160 }
4161 $mailsender->MailMsg({to =>$mailaddress, subject => "Actual PNL System Error!", msg => "$finalerrorstring" })
4162 or die "$Mail::Sender::Error\n";
4163}
4164
4165# Diagnostic Framework - To be implemented in the future
4166#sub InitiateDOD {
4167# PrintOutStd("============================\n");
4168# PrintOutStd("Diagnostics On Death for ID $ledgerid\n");
4169# PrintOutStd("============================\n");
4170#}