/* Copyright (c) 2005-2025 Tachyon Design Automation Corp. */

/* === INSERT LICENSE ===
ib_ytd_anal program for analyzing Interactive Brokers format downloaded
Year to Date .csv format spread sheet file.

Copyright © 2005-2026 Tachyon Design Automation Corp.
All Rights reserved.  Licensed software subject to prohibitions and
restrictions.

The intent of this document is to state the conditions under which the
ib_ytd_anal trade analysis C program may be copied and executed such that
the Copyright Holder Tachyon Design Automation maintains distribution and
artistic control over the use and development as granted by Copyright law. 

Licensee may make modifications to ib_ytd_anal for internal use.  ib_ytd_anal
may not be sold without obtaining a sales license from Tachyon DA. 
All forms of indirect sales such as bundling or executing on a shared
cloud are prohibited.  Other uses of ib_ytd_anal program require written
permission from Tachyon Design Automation.

 DISCLAIMER OF WARRANTIES: THIS SOFTWARE IS PROVIDED "AS IS" AND
WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION,
THE IMPLIED WARRANTIES OF MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE,
OR NON-INFRINGEMENT.  THE COPYRIGHT HOLDER SHALL NOT BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY
OUT OF THE USE OF THE SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.

=== END INSERT === */

/*
 * routine for IB to output reports from built and filled in tran tab
 */

#include <stdio.h>
#include <time.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <pthread.h>
#include <ctype.h>
#include <math.h>

#include "newport.h"

#ifdef __DBMALLOC__
#include "../malloc.h"
#endif

static void calc_sip_flds(void);
static void calc_bas_sip_flds();
static void accum_1sip_bas_flds(struct symndx_t *,
 struct symndx_t *);
static void calc_symndx_divs(void);
static void set_symndx_acru_divs(struct symndx_t *);

static void prt_cl_tr_msg(struct symndx_t *, int32);
static void pr_still_op_tr_msg(struct symndx_t *, int32 op_tri,
 struct trans_t *);
static void prt_bas_all_insts_stats(void);
static char * bld_mth_tab_str(char *, double *);
static char *get_recent_op_dt(char *, int32, struct symndx_t *); 
static char *get_recent_cl_dt(char *, int32, struct symndx_t *); 
static void write_all_stk_acru_divs(void);
static void write_fee_and_int_totals(void);
static void calc_various_totals(void);

extern void  __wr_newport_cod_trans_file(void);
extern void __fill_sip_flds(void);
extern double __smult(struct trans_t *);
extern int32 __get_fld_digs(struct trans_t *);
extern void  __wr_ib_cod_trans_file(void);
extern void __prt_port_pandl(void);
extern void __init_prt_rpt_tot_flds(struct trans_t *);
extern void __init_symndx(struct symndx_t *);
extern void __add_to_end_trans(struct trans_t *);
extern void __add_to_end_symndx(struct symndx_t *);
extern void __bld_ndx_opos_trans(void);
extern int32 __fnd_trtab_by_trtyp(char *, int32, int32);
extern int32 __fnd_1st_unpaired_acru_trans(char *sym);
extern int32 __fnd_latest_div_pay_trans(char *); 
extern struct symndx_t *__fnd_bassym_symndx(char *);
extern int32 __bld_ib_csv_flds(void);
extern int32 __fnd_ch_in_trans_cod(char *, char);
extern char __cod_opcl_ch(char *);
extern void __init_prt_rpt_tot_flds(struct trans_t *);
extern char *__int_to_acct_type_str(int32);
extern char *__int_to_cur_type_str(int32);
extern int32 __dash_num_date_to_datrec(char *, struct date_t *);
extern int32 __ib_time_to_clktim(char *, struct clktime_t *);
extern int32 __month_abbrev_to_num(char *);
extern char *__mth_num_to_mthabrv(char *, int32);
extern char * __mth_num_to_fut_let(char *, int32);
extern void __init_dat(struct date_t *);
extern char *__dt_to_string(char *, struct date_t *);
extern int32 __cmp_dt(const struct date_t *, const struct date_t *);
extern void __init_clktim(struct clktime_t *);
extern char *__int_to_acct_type_str(int32);
extern char *__int_to_ityp_str(int32);
extern int32 __trade_is_open(char *);
extern char *__my_malloc(size_t);
extern void __msg(char *, ...);
extern void __misc_terr(char *, int32);
extern void __fwarn(int32, char *, ...);
extern void __ferr(int32, char *, ...);
extern void __terr(int32, char *, ...);
extern void __case_terr(char *, int32);
extern void __arg_terr(char *, int32);
extern void __my_vfprintf(FILE *, char *, va_list);

/*
 * ROUTINES TO DUMP ASCII FILE FROM TRANSACTION TAB
 */

/* ====
// must be first line of file
St None None GDt=11-01-20 GTim=23:10:0 FrDt=01-02-20 ToDt=11-01-20
 ==> format of file output
 // - open file
 // - go through writing records
// can build table of fut mulipliers to dollars
Tr Stk CPG A=Ib Dt=07-26-20 Cd=O  Bquan=600 Pr=3.1975 Com=4.1096 
Tr Opt AGNC A=Sch Dt=07-26-20 Cd=O Sq=1 Xdt=10-16-20 Spr=14 O=P Pr=3.1975 Com=4.1096 
Tr Fut MES A=Ira Dt=007-28-20 Cd=C,P Bq=1 Pr=3450.0 Comm=1.25
Tr FOpt MES A=Sch Dt=10-11-20 Cd=O Bq=1 Xdt=12-07-20 Spr=3450.0 O=C Pr=3.50 Com=0.50 Cur=GBP

// date for these is day report run - today
// long is Bquan and short is quan
OPos Stk CPG A=Sch Bq=1600 OPr=1.27 CPr=1.30  
OPos Opt AGNC A=Ib Bq=1 Xdt=10-22-20 Spr=14 OPr=0.50 CPr=0.30
Opos Fut MES A=Ib Bq=1 OPr=3450.0 CPr=3490.0

// instrument is Cr/Deb - symbol is fee type
// ===>
Fee Deb US A=IB DT=03-20-20 Amt=120.00
Fee Deb CFE a=Sch DT=01-02-20 Amt=3.59 

Div Cr AGNC A=Si DT=08-10-12 Pr=0.12 Amt=120.0
Div Deb AGNC A=Ib DT=12-10-12 Pr=0.18 Amt=120.0

InLDiv Cr AGNC A=Ib
InlDiv Deb AGNC

- this is withholding tax that think need to just skip 
Tax Deb AGNC
Tax Cr AGNC

Int Cr None
Int Deb None

Dep Cr Chk
Withd Deb Wire

Bal None None Dt=03-05-20 Amt=3333.33

=== */

/*
 * write the coded transaction file for start of year through today
 */
extern void  __wr_newport_cod_trans_file(void)
{
 int32 tri;
 double rlzgain;
 struct trans_t *trp;
 char s1[RECLEN], s2[RECLEN], sstr[RECLEN], dtstr[RECLEN];

 if ((__trout_s = fopen(__cod_trans_fnam, "w")) == NULL) 
  {
    __misc_terr(__FILE__, __LINE__);
  }

 /* file starts with a stmt record */
 /* St None None GDt=11-01-20 GTim=23:10:0 FrDt=01-02-20 ToDt=11-01-20 */
 __dt_to_string(dtstr, &(__when_gen_dat));
 sprintf(s1, "%02d%02d%02d", __when_gen_tim.hr, __when_gen_tim.min,
  __when_gen_tim.sec);
 fprintf(__trout_s, "St None None A=%s Gdt=%s GTim=%s", __brkrnam, dtstr, s1);
 __dt_to_string(dtstr, &(__codfil_start_dat)); 
 __dt_to_string(s1, &(__codfil_end_dat)); 
 fprintf(__trout_s, " FrDt=%s ToDt=%s\n", dtstr, s1);

 for (tri = 0; tri <= __last_trani; tri++)
  {
   trp = __trantab[tri];
   switch (trp->tr_typ) { 
    case TRTYP_TRADE:
     if (strcmp(trp->sort_sym, "") != 0) strcpy(sstr, trp->sort_sym);
     else strcpy(sstr, trp->symbol);
     strcpy(s1, __int_to_ityp_str(trp->tr_ityp));
     __dt_to_string(dtstr, &(trp->tdate));
     if (trp->is_buy) strcpy(s2, "Bq"); else strcpy(s2, "Sq");
     /* SJM 12-26-21 - field size defaults to 6 - this makes 10 but */
     /* will truncate if longer */
     fprintf(__trout_s, "Tr %s %s Dt=%s Cd=%s %s=%.2lf", sstr,
      s1, dtstr, trp->tr_code, s2, trp->tr_quant);
/* === use full sym for opt/fut/futopt
     if (trp->tr_ityp == TRITYP_OPT || trp->tr_ityp == TRITYP_FUTOPT)
      {
       __dt_to_string(dtstr, &(trp-> opt_exp_dt));
       if (trp->is_put_opt) strcpy(s1, "P"); else strcpy(s1, "C");
       fprintf(__trout_s, " Xdt=%s Spr=%.2f O=%s Pr=%.2lf Com=%.2lf",
        dtstr, trp->opt_strike, s1, trp->tr_price, trp->tr_comm);
      }
     else
      {
       fprintf(__trout_s, " Pr=%.2lf Com=%.2lf", trp->tr_price, trp->tr_comm);
      }
=== */
     fprintf(__trout_s, " Pr=%.2lf Com=%.2lf", trp->tr_price, trp->tr_comm);
     rlzgain = trp->cl_gain_per_sh*fabs(trp->tr_quant); 
     if (rlzgain != 0)
      sprintf(s2, " tr rlzg=%.2lf", rlzgain);
     else strcpy(s2, "");
     if (trp->this_still_op < 0.0)
      {
       fprintf(__trout_s, " Shrt=%.2lf%s%s", trp->this_still_op,
        s1, s2);
      }
     else fprintf(__trout_s, " Lng=%.2lf%s%s", trp->this_still_op,
      s1, s2);
     break;
    case TRTYP_OPPOS:
     strcpy(s1, __int_to_ityp_str(trp->tr_ityp));
     __dt_to_string(dtstr, &(trp->tdate));
     fprintf(__trout_s, "Opos %s %s Dt=%s Quant=%.2lf",
      trp->symbol, s1, dtstr, trp->tr_quant);
     if (trp->tr_ityp == TRITYP_OPT || trp->tr_ityp == TRITYP_FUTOPT)
      {
       __dt_to_string(dtstr, &(trp->opt_exp_dt));
       if (trp->is_put_opt) strcpy(s1, "P"); else strcpy(s1, "C");
       fprintf(__trout_s, " Xdt=%s Spr=%.2lf O=%s OPr=%.2lf CPr%.2lf",
        dtstr, trp->opt_strike, s1, trp->tr_price, trp->tr_tdy_closepr);
      }
     else
      {
       fprintf(__trout_s, " OPr=%.2lf CPr=%.2lf", trp->tr_price,
        trp->tr_tdy_closepr);
      }
     break;
    case TRTYP_FEE:    
     if (trp->tr_ityp == TRITYP_DEBIT) strcpy(s1, "Deb");
     else if (trp->tr_ityp == TRITYP_CREDIT) strcpy(s1, "Cre");
     else __case_terr(__FILE__, __LINE__);
     __dt_to_string(dtstr, &(trp->tdate));
     fprintf(__trout_s, "Fee %s %s Dt=%s Amt=%.2lf", s1,
      trp->symbol, dtstr, trp->tr_amount);
     break;
    case TRTYP_DIV:
     if (trp->tr_ityp == TRITYP_CREDIT) strcpy(s1, "Cre");
     else if (trp->tr_ityp == TRITYP_DEBIT) strcpy(s1, "Deb");
     else __case_terr(__FILE__, __LINE__);
     __dt_to_string(dtstr, &(trp->tdate));
     /* div. per share is Pr with amount total div - do not know quant here */
     fprintf(__trout_s, "Div %s %s Dt=%s Pr=%.2lf Amt=%.2lf", s1,
      trp->symbol, dtstr, trp->tr_price, trp->tr_amount);  
     break;
    case TRTYP_DIVACRU:
// SJM 11-09-25 WRITEME
     /* SJM 01-03-21 - ignoring output of xdiv records for now */
     continue;
    case TRTYP_INLIEU_DIV:
     /* SJM 01-03-21 - for now ignore inlieu - missing combining code? */
     continue;
     /* SJM 10-19-20 - LOOKATME - this is for where no non in lieu */
     if (trp->tr_ityp == TRITYP_CREDIT) strcpy(s1, "Cre");
     else if (trp->tr_ityp == TRITYP_DEBIT) strcpy(s1, "Deb");
     else __case_terr(__FILE__, __LINE__);
     __dt_to_string(dtstr, &(trp->tdate));
     /* div. per share is Pr with amount total div - do not know quant here */
     fprintf(__trout_s, "InLDiv %s %s Dt=%s Amt=%.2lf", s1,
      trp->symbol, dtstr, trp->tr_amount);  
     break;
    case TRTYP_TAX:
     /* withholding tax */
     __dt_to_string(dtstr, &(trp->tdate));
     /* SJM 10-20-20 - LOOKATME - maybe can extract per share div from this */
     fprintf(__trout_s, "Tax Deb %s Dt=%s Amt=%.2lf",
      trp->symbol, dtstr, trp->tr_amount);  
     break;
    case TRTYP_DEPOSIT:
     __dt_to_string(dtstr, &(trp->tdate));
     /* SJM 10-20-20 - for now no way to distinguish checks from wires */
     fprintf(__trout_s, "Dep Cr Wire Dt=%s Amt=%.2lf",
      dtstr, trp->tr_amount);  
     break;
    case TRTYP_WITHDRAW:
     __dt_to_string(dtstr, &(trp->tdate));
     /* with drawal amount minus */
     /* SJM 10-20-20 - for now no way to distinguish checks from wires */
     fprintf(__trout_s, "Withd Deb Wire Dt=%s Amt=%.2lf",
      dtstr, trp->tr_amount);  
     break;
    case TRTYP_INTEREST:
     /* for GBP this will have GBP bit on */
     __dt_to_string(dtstr, &(trp->tdate));
     if (trp->tr_amount < 0) strcpy(s1, "Deb"); else strcpy(s1, "Cr");
     fprintf(__trout_s, "Int %s %s None Dt=%s Amt=%.2lf", s1,
      trp->symbol, dtstr, trp->tr_amount);  
     break;
    case TRTYP_BALANCE:
     /* know this will always not be GBP */
     __dt_to_string(dtstr, &(trp->tdate));
     fprintf(__trout_s, "Bal None None Dt=%s Amt=%.2lf",
      dtstr, trp->tr_amount);  
     break;
    default: __case_terr(__FILE__, __LINE__);
   }
  /* SJM 0l-25-21 - need cur type for records */
  if (trp->cur_typ != CUR_USD)
   {
    fprintf(__trout_s, " Cur=%s\n", __int_to_cur_type_str(trp->cur_typ));
   }
  else fprintf(__trout_s, "\n");
 }
 fclose(__trout_s);
}

/*
 * ROUTINES TO CALC TOTALS FOR SIPS AND ALL of SAME BASE SYMBOL
 */

/*
 * wrapper to call procs to calc sip fields
 */
extern void __fill_sip_flds(void)
{
 calc_sip_flds();
 calc_symndx_divs();
 calc_bas_sip_flds();
}

/*
 * accumulate for each cl trade in sip the rlz gain
 *
 * here to get totals in dollars must call s mult 
 */
static void calc_sip_flds(void)
{
 int32 si, tri, ltri;
 struct trans_t *trp, *ltrp;
 struct symndx_t *sip;
 char codch;

 /* for each sip calc gain */
 /* gain per sh and no. shares set for every close */
 for (si = 0; si <= __last_symndxi; si++)
  {
   sip = __symndx[si];
   for (tri = sip->tr_bi; tri <= sip->tr_ei; tri++)
    {
     trp = __trantab[tri];
     /* add for all cl option trades */
     codch = __cod_opcl_ch(trp->tr_code);
     if (codch == 'O') continue;
     /* only stocks can possibly have acrued unpaid div */
     if (tri == sip->tr_ei && trp->tr_ityp == TRITYP_STOCK)
      {
       set_symndx_acru_divs(sip);
       if (trp->tdy_pseudo_cl)
        {
         /* only set last div for open symndx recs */
         ltri = __fnd_latest_div_pay_trans(trp->symbol);
         if (ltri != -1)
          { 
           ltrp = __trantab[ltri];
           sip->bas_ldiv_persh = ltrp->tr_xdiv_amt/trp->tr_quant;
           sip->bas_last_div_pay_dt = ltrp->div_pay_dt; 
          }
        }
      }
     if (trp->tdy_pseudo_cl)
      {
       /* pseudo cl is gain as if closed tdy */
       sip->unrlz_gain = (trp->cl_gain_per_sh*fabs(trp->tr_quant)
        *__smult(trp));;
       if (trp->tr_ityp == TRITYP_OPT
        || trp->tr_ityp == TRITYP_FUTOPT)
        { 
         /* this is one last pseudo cl - really open today */ 
         sip->opt_unrlz_gain
          = (trp->cl_gain_per_sh*fabs(trp->tr_quant)*__smult(trp));
         /* SJM 12-17-25 - pseudo cl buy is short option */ 
         /* wrong since ignoring spread long opt decay */
         if (trp->is_buy)
          {
           sip->opt_pot_income = trp->tr_tdy_closepr*fabs(trp->tr_quant)
            *__smult(trp);
          }
        }
       continue;
      }
     /* rlz gain for one sip instrument tot since all opt or stk/fut */
     sip->rlzgain_tot += (trp->cl_gain_per_sh*fabs(trp->tr_quant)
      *__smult(trp));;
     sip->mth_rlzgain[trp->tdate.month]
       += (trp->cl_gain_per_sh*fabs(trp->tr_quant)*__smult(trp));
     if (trp->tr_ityp == TRITYP_OPT
      || trp->tr_ityp == TRITYP_FUTOPT)
      {
       sip->rlz_traded_opts += fabs(trp->tr_quant);
      }
     else sip->rlz_traded_shares += fabs(trp->tr_quant);
    } 
  }
}

/*
 * calc the bas totals 
 *
 * total in sips also adding mth tabs
 * since use flds from ins totals, do not need to call s mult
 */
static void calc_bas_sip_flds(void)
{
 int32 si, sgi, si2;
 struct symndx_t *sip, *sip2;

 /* now calc the same bas sym totals */
 for (si = 0; si <= __last_symndxi; si++)
  {
   sip = __symndx[si];
   if (!sip->sip_bas) continue;
   accum_1sip_bas_flds(sip, sip);
   sip->num_bas_ins = 1;
   sgi = sip->bas_sgrp_ndxi;
   /* already processed sip bas member of group (equiv class) */
   for (sgi++;;sgi++)   
    {
     /* possible to have one one symndx in sgr */
     si2 =  __basgrpndx[sgi];   
     if (si2 ==  -1) break;
     sip2 = __symndx[si2];
     sip->num_bas_ins += 1;
     accum_1sip_bas_flds(sip, sip2);
    }
  }
}

/*
 * accum to base sip from a non base sip fields
 *
 * for actual bas (can be an option if not stk/fut trades)
 * will move flds from sip non base to sip base since init to 0
 * first can be accum  
 *
 * bas uses sip per instrument tots so do not need to call smult
 */
static void accum_1sip_bas_flds(struct symndx_t *sip,
 struct symndx_t *sip2)
{
 int32 mi;
 struct trans_t *etrp2;

 /* init first - these are bas totals */
 sip->bas_rlzgain_tot += sip2->rlzgain_tot;
 sip->bas_rlz_traded_shares += sip2->rlz_traded_shares;
 sip->bas_rlz_traded_opts += sip2->rlz_traded_opts;
 /* copy per mth tab rlz gain to bas rlz gain for sip bas sip */
 if (sip2->rlzgain_tot != 0)
  {
   for (mi = 1; mi <= __cur_mth_num; mi++)
    {
     sip->bas_mth_rlzgain[mi] += sip2->mth_rlzgain[mi];
    }
   }
 /* etrp2 just used to determine is sip underlying is option */
 etrp2 = __trantab[sip2->tr_ei]; 
 /* if accumulating 2nd op is option, update bas opt flds too */
 if (etrp2->tr_ityp == TRITYP_OPT || etrp2->tr_ityp == TRITYP_FUTOPT)
  { 
   sip->bas_opt_rlzgain_tot += sip2->rlzgain_tot;
   for (mi = 1; mi <= __cur_mth_num; mi++)
    {
     sip->bas_opt_mth_rlzgain[mi] += sip2->mth_rlzgain[mi];
    }
   }
 /* if not open (no pseudo cl trans) un rlz gain will be 0 */
 sip->bas_all_unrlz_gain += sip2->unrlz_gain;

 /* now init the bas open flds because sip2 has an op pseudo cl*/
 if (etrp2->tr_ityp == TRITYP_OPT || etrp2->tr_ityp == TRITYP_FUTOPT)
  {
   if (etrp2->tdy_pseudo_cl)
    {
     /* pseudo cloase means open */
     sip->bas_open_opt_num++;
    } 
   sip->bas_op_opt_unrlz_gain += sip2->opt_unrlz_gain;
   sip->bas_opt_pot_income += sip2->opt_pot_income;
  }
 /* add to sip (the base) open current dollar value for both opts and stk/fut `*/
 /* for long the pseudo cl is a sell */
 if (etrp2->tdy_pseudo_cl && !etrp2->is_buy)
  {
   sip->bas_investment_tot +=
     abs(etrp2->tr_quant)*etrp2->tr_price*__smult(etrp2);
  }
}

/*
 * calc dividend totals to be put in symndx ytd_divs fields
 * no base sym totals just for stocks
 *
 * fills sym ndx ytd divs field
 * goes through div records to add to sym ndx rec
 *
 * also calc total dividends for all syms in tran tab for this run
 * and totals divs by month
 *
 * key to this is all div records in tran tab div trans type records
 * SJM 04-02-22 - what about in liue part of divs?
 */
static void calc_symndx_divs(void)
{
 int32 ti;
 struct trans_t *trp, *btrp;
 struct symndx_t *sip;

 __ytd_tot_divs = 0.0;
 for (ti = 0; ti <= __last_trani; ti++)
  { 
   trp = __trantab[ti];
   if (trp->tr_typ != TRTYP_DIV) continue;

   /* only symndx entries where base symbol is stock */
   sip = __fnd_bassym_symndx(trp->symbol);
   /* DBG remove --- */
   if (sip == NULL) __misc_terr(__FILE__, __LINE__);
   /* --- */
   btrp = __trantab[sip->tr_bi];
   /* DBG remove --- */
   if (!sip->sip_bas) __misc_terr(__FILE__, __LINE__);
   if (btrp->tr_ityp != TRITYP_STOCK)
    {
     /* futures always have divs built into pr - opts no divs */
      __misc_terr(__FILE__, __LINE__);
    }
   /* --- */
  
   if (strcmp(trp->sort_sym, sip->ndxsnamp) != 0)
    __misc_terr(__FILE__, __LINE__);
   __ytd_tot_divs += trp->tr_amount;
   sip->ytd_tot_divs += trp->tr_amount;
   sip->mth_divs[trp->tdate.month] += trp->tr_amount;
   __mth_tot_divs[trp->tdate.month] += trp->tr_amount;
  }
}

/*
 * set symndx not paid accr div flds
 * only called for stock sips so ndxsnamp always base not sort sym
 *
 * a last close that is not a pseudo cl may have a unpaid xdiv
 * pattern is xdiv, close rest of shares, xdiv still paid
*/
static void set_symndx_acru_divs(struct symndx_t *sip)
{
 int32 potri, cv;
 struct trans_t *potrp;

 potri = __fnd_1st_unpaired_acru_trans(sip->ndxsnamp); 
 /* no unpaid xdivs or not a  dividend payer */
 if (potri == -1) return;

 /* pay date must be today or after */
 potrp = __trantab[potri];
 cv = __cmp_dt(&(potrp->div_pay_dt), &(__codfil_end_dat));
 if (cv < 0) __misc_terr(__FILE__, __LINE__);
 /* this is a not paid acru with pay date today or after */
 sip->op_xdiv_dt = potrp->xdiv_dt;
 sip->op_div_pay_dt = potrp->div_pay_dt;
 sip->open_stk_acru_div = potrp->tr_xdiv_amt; 
}

/*
 * output the pandl report
 * also accumulates sym ndx symbols totals
 *
 * this also sets rlz gain field for closes trades
 * and op unrlz gain fld for last pseudo cl if present
 */
extern void __prt_port_pandl(void)
{
 int32 si, tri, nd;
 struct trans_t *trp, *etrp;
 struct symndx_t *sip;
 char codch, s1[RECLEN], mthdivstr[RECLEN], mthtotstr[RECLEN];

 /* dump the sym ndx entire period profits and losses */
 /* also calculate YTD total */
 __ytd_open_gain = 0.0;
 /* print closed or today open p/l line for each instrument */
 /* separate cl/op trade lines with blank line */
 __msg("\n");
 for (si = 0; si <= __last_symndxi; si++)
  {
   sip = __symndx[si];

   /* print one msg for every close - exclude pseudo cl here */
   for (tri = sip->tr_bi; tri <= sip->tr_ei; tri++)
    {
     trp = __trantab[tri];
     /* if last one is really open pseudo cl then done */
     if (tri == sip->tr_ei && trp->tdy_pseudo_cl) break;

     codch = __cod_opcl_ch(trp->tr_code);
     if (codch == 'O') continue;
     /* DBG remove -- */
     if (trp->tr_quant == 0.0) __misc_terr(__FILE__, __LINE__);
     /* --- */
     prt_cl_tr_msg(sip, tri);
    }

   etrp = __trantab[sip->tr_ei];
   nd = __get_fld_digs(etrp);
   if (etrp->tdy_pseudo_cl)
    {
     /* DBG removee --- */
     codch = __cod_opcl_ch(etrp->tr_code);
     if (codch != 'C') __misc_terr(__FILE__, __LINE__);
     /* --- */

     /* first if has open - print msg */
     // prt_cl_tr_msg(sip, tri);
     pr_still_op_tr_msg(sip, sip->tr_ei, etrp);
    }

   /* print the per instrument tots and mth tots and divs */
   if (etrp->tr_ityp == TRITYP_STOCK || etrp->tr_ityp == TRITYP_FUT)
    {
     if (sip->rlz_traded_shares != 0)
      {
       bld_mth_tab_str(mthtotstr, &(sip->mth_rlzgain[0])); 
       if (etrp->tr_ityp == TRITYP_FUT) strcpy(s1, "FUTURES");
       else strcpy(s1, "SHARES");
       __msg(
        "SYM %s %.2lf %s TOT GAIN %.*lf\n   PER MTH: %s\n",
        sip->ndxsnamp, sip->rlz_traded_shares, s1, nd, sip->rlzgain_tot,
        mthtotstr);

       if (etrp->tr_ityp == TRITYP_STOCK)
        {
         if (sip->ytd_tot_divs != 0)
          {
           bld_mth_tab_str(mthdivstr, &(sip->mth_divs[0])); 
           __msg("   TOT DIVS %.2lf PER MTH: %s\n",
            sip->ytd_tot_divs, mthdivstr);
          }
         /* for both closed after xdiv and open */
        } 
       __msg("\n");
      }
     else __msg("\n");
    } 
   else
    {
     /* print option total for this symndx symbol - not base */
     if (sip->rlz_traded_opts != 0)
      {
       bld_mth_tab_str(mthtotstr, &(sip->mth_rlzgain[0])); 
       __msg("SYM CL %s %ld OPTIONS TOT GAIN %.*lf\n   PER MTH: %s\n",
        sip->ndxsnamp, sip->rlz_traded_opts, nd, sip->rlzgain_tot,
        mthtotstr);
        __msg("\n");
       }
      else __msg("\n");
    } 
  }
 /* next print bas sym totals - if no stk/fut trades first option */
 prt_bas_all_insts_stats();
 write_all_stk_acru_divs();

 /* FROM HERE PORTFOLIO STATS INCLUDING IN .csv FILE DIRECT IB VALUES */
 /* SJM 11-28-22 - IB YTD file values - see if balance */
 __msg("\n");
 __msg(">>> IB: Begin Year Starting NAV %.2lf\n", __start_nav);
 __msg(">>> IB: YTD Mark-to-Market (profit?) %.2lf\n", __end_mtm_profit);
 __msg(">>> IB: YTD Time Weighted Profit Percent %.2lf%%\n",
  __ib_weight_pct_gain);
 __msg(">>> IB: YTD IB Total P/L %.2lf\n", __tot_ib_ytd_pandl);
 __msg(">>> IB: YTD Net Deposits and Withdrawals %.2lf\n",
  __end_dep_and_wdraw);
 __msg(">>> IB: Ending Cash (all currencies) %.2lf\n", __ib_end_settled_cash);

 __msg(">>> IB: YTD Dividends %.2lf (includes in lieu)\n", __end_ib_divs);
 __msg(">>> IB: YTD Interest %.2lf\n", __end_ib_interest);
 __msg(">>> IB: Today MTM NAV %.2lf\n", __end_nav);
 calc_various_totals();

 /* open totals */
 __msg(">>> Total all open gain %.2lf\n", __ytd_open_gain);
 __msg(">>> Total open stock gain %.2lf\n", __ytd_open_stk_gain);
 __msg(">>> Total open future gain %.2lf\n", __ytd_open_fut_gain);
 __msg(">>> Total open option gain %.2lf\n", __ytd_open_opt_gain);
  __msg(">>> Total open futopt gain %.2lf\n",
   __ytd_open_futopt_gain);
  __msg(">>> Potential income: option %.2lf futopt %.2lf tot %.2lf\n",
   __tot_opt_pot_income, __tot_futopt_pot_income,
   __tot_opt_pot_income + __tot_futopt_pot_income);
  __msg("\n");

 __msg(">>> Total all realized gain %.2lf\n", __tot_ytd_rlz_gain);
 bld_mth_tab_str(mthtotstr, &(__mth_tot_rlz_gain[0]));
 __msg("Per mth all gain: %s\n", mthtotstr);

 __msg(">>> Total stock realized gain %.2lf\n", __mth_stk_rlz_gain);
 bld_mth_tab_str(mthtotstr, &(__mth_stk_rlz_gain[0]));
 __msg("Stock per mth gain: %s\n", mthtotstr);
// ==> by month

 __msg(">>> Total future realized gain %.2lf\n", __tot_fut_rlz_gain);
 bld_mth_tab_str(mthtotstr, &(__mth_fut_rlz_gain[0]));
 __msg("Future per mth gain: %s\n", mthtotstr);

 __msg(">>> Total option realized gain %.2lf\n", __tot_opt_rlz_gain);
 bld_mth_tab_str(mthtotstr, &(__mth_opt_rlz_gain[0]));
 __msg("Option per mth gain: %s\n", mthtotstr);

 __msg(">>> Total future option realized gain %.2lf\n",
  __tot_futopt_rlz_gain);
 bld_mth_tab_str(mthtotstr, &(__mth_futopt_rlz_gain[0]));
 __msg("Future option per mth gain: %s\n", mthtotstr);

 __msg(
  ">>> Total ACCRUED after Xdiv day but not paid divs: %.2lf\n",
  __tot_open_acru_divs);
 __msg(">>> YTD dividends %.2lf: ", __ytd_tot_divs);
 bld_mth_tab_str(mthtotstr, &(__mth_tot_divs[0]));
 __msg("Per mth divs: %s\n", mthtotstr);
 __msg("\n");
 write_fee_and_int_totals();
// interest plus dividends 
 __ytd_tot_income = __ytd_tot_divs + __ytd_tot_int;
 __msg(">>> YTD total income %.2lf\n", __ytd_tot_income);

/* ========== SJM 08-26-25 WHATSHOULDTHISBE
// open pos values
 __msg(" >>> Today total open net value %.2lf and gross value %.2lf\n",
  __tot_tdy_net_val, __tot_tdy_gross_val);


 tot_cl_val_increase = __tot_ytd_rlz_gain + __ytd_tot_income
  - __ytd_tot_debits;
 __msg(
  ">>> Closed val increase %.2lf tot close+open gain %.2lf\n",
  tot_cl_val_increase, tot_cl_val_increase + __ytd_open_gain);
===== */

 /* SJM 08-30-25 - new try at printing PandL */
 __msg("\n");
 __msg("closed stk/fut trading gain %.2lf\n",
  __tot_stk_rlz_gain + __tot_fut_rlz_gain);
 __msg("Open stk/fut trading gain %.2lf\n",
  __ytd_open_stk_gain + __ytd_open_fut_gain);
__msg("closed option sold premium (includes buy gain/loss) %.2lf\n",
  __tot_opt_rlz_gain + __tot_futopt_rlz_gain);
 __msg("open option sold premium (spread calls ignored) %.2lf\n",
  __ytd_open_opt_gain + __ytd_open_futopt_gain); 
  __msg("Div received (in lieu excluded) %.2lf\n",
  __ytd_tot_divs); 
  __msg("Net interest received %.2lf\n", __ytd_tot_int);
  __msg("IB total cash added/removed %.2lf\n", __end_dep_and_wdraw);
  __msg("IB Today available cash (USD only) %.2lf\n", __ib_end_settled_cash);
 __msg("YTD expenses %.2lf\n", __ytd_tot_debits);
 __msg("YTD profit %.2lf\n", 
  __tot_ytd_rlz_gain + __ytd_open_gain + __ytd_tot_divs
  + __ytd_tot_income + __end_dep_and_wdraw + __ytd_tot_debits);
}

/*
 * ROUTINES TO PRINT INSTRUMENT CLOSED TRADES
 */

/*
 * print 2 lines for each closed trade
 * this sets nd (num digits for currency futures particularly)
 */
static void prt_cl_tr_msg(struct symndx_t *sip, int32 tri)
{
 int32 nd;
 struct trans_t *trp;
 double op_sh_num, gain_per_sh, pct_gain;
 char dirstr[RECLEN], opstr[RECLEN], clstr[RECLEN];
 char lstopstr[RECLEN], lstclstr[RECLEN];
 
 trp = __trantab[tri];
 op_sh_num = fabs(trp->tr_quant);
 gain_per_sh = trp->cl_gain_per_sh;
 if (trp->is_buy)
  {
   /* buy to close a short */ 
   strcpy(dirstr, "short");
   strcpy(opstr, "sell");
   strcpy(clstr, "buy");
  }
 else  
  {
   /* sell to close a long */ 
   strcpy(dirstr, "long");
   strcpy(opstr, "buy");
   strcpy(clstr, "sell");
  }

 get_recent_op_dt(lstopstr, tri, sip); 
 /* want to see activity is this cl after previous cl */
 get_recent_cl_dt(lstclstr, tri, sip);
 nd = __get_fld_digs(trp);
 pct_gain = 100.0*gain_per_sh/trp->op_avg_sh_pr;   
 __msg("CL %02d/%02d %s %.2lf %s last op %s near cl %s\n",
  trp->tdate.month, trp->tdate.day, trp->sort_sym,
  op_sh_num, dirstr, lstopstr, lstclstr);

 __msg(
  " %s %.*lf (%.2lf) %s %.*lf (%.2lf) gain %.*lf (%.2lf) %.2lf%%\n",
  opstr, nd,
  trp->op_avg_sh_pr, op_sh_num*trp->op_avg_sh_pr*__smult(trp),
  clstr, nd,
  trp->tr_price, op_sh_num*trp->tr_price*__smult(trp),
  nd, gain_per_sh, gain_per_sh*op_sh_num*__smult(trp), pct_gain);
}

/*
 * print 2 lines for any remaing open shares gain
 * this is a pseudo close that look same as normal cl - as if cl tdy
 * pseudo cl does not have tr price must use tr tdy closepr
 */
static void pr_still_op_tr_msg(struct symndx_t *sip, int32 end_tri,
 struct trans_t *trp)
{
 int32 nd;
 double op_sh_num, gain_per_sh, pct_gain;
 char dirstr[RECLEN], opstr[RECLEN];
 char lstopstr[RECLEN], lstclstr[RECLEN];

 op_sh_num = fabs(trp->tr_quant);
 if (trp->is_buy)
  {
   /* open pos short - pseudo tr is buy to close */
   gain_per_sh = trp->op_avg_sh_pr - trp->tr_tdy_closepr;
   strcpy(dirstr, "short");
   strcpy(opstr, "sell");
  }
 else  
  {
   /* open long - pseudo tr is sell to close */
   gain_per_sh = trp->tr_tdy_closepr - trp->op_avg_sh_pr;
   strcpy(dirstr, "long");
   strcpy(opstr, "buy");
  }
 pct_gain = 100.0*gain_per_sh/trp->op_avg_sh_pr;   
 get_recent_op_dt(lstopstr, end_tri, sip); 
 get_recent_cl_dt(lstclstr, end_tri, sip); 
 nd = __get_fld_digs(trp);
 __msg("OPN %s %s %.2lf last op %s nr cl %s\n", 
  trp->sort_sym, dirstr, op_sh_num,
   lstopstr, lstclstr);

 __msg(" avg %s %.*lf (%.2lf) tdy %.*lf (%.2lf) gain %.*lf (%.2lf) %.2lf%%\n", 
  opstr, nd, trp->op_avg_sh_pr,
  op_sh_num*trp->op_avg_sh_pr*__smult(trp),
  nd, trp->tr_tdy_closepr, trp->tr_tdy_closepr*op_sh_num*__smult(trp),
  nd, gain_per_sh, gain_per_sh*op_sh_num*__smult(trp), pct_gain);
 trp->op_unrlz_gain = gain_per_sh*op_sh_num*__smult(trp);
}

/*
 * all trades of both underlying and options for bas symbol
 */
static void prt_bas_all_insts_stats(void)
{
 int32 si;
 struct symndx_t *bsip;
 struct trans_t *etrp;
 char s1[RECLEN], mthtotstr[RECLEN], mthdivstr[RECLEN];

 for (si = 0; si <= __last_symndxi; si++)
  {
   bsip = __symndx[si];
   if (!bsip->sip_bas) continue;
     
   etrp = __trantab[bsip->tr_ei];
   if (bsip->bas_all_unrlz_gain) strcpy(s1, " OPEN");
   else strcpy(s1, "");

   __msg("\nBAS%s %s (%.0ld ins) TOT RET %.2lf rlz %.2lf unrlz %.2lf\n",
    s1, bsip->ndxsnamp, bsip->num_bas_ins,
    bsip->bas_rlzgain_tot + bsip->bas_all_unrlz_gain + bsip->ytd_tot_divs,
    bsip->bas_rlzgain_tot, bsip->bas_all_unrlz_gain);

// ====
  if (etrp->tr_ityp == TRITYP_FUT || etrp->tr_ityp == TRITYP_FUTOPT) 
   {
     __msg(
      "   future open %.lf gain %.2lf fut closed  %.2lf rlz gain %.2lf\n",
      -etrp->tr_quant,
      bsip->bas_all_unrlz_gain - bsip->bas_op_opt_unrlz_gain, 
      bsip->bas_rlz_traded_shares,
      bsip->bas_rlzgain_tot - bsip->bas_opt_rlzgain_tot);
   }
// ===
  else
   {
// ====
if (etrp->tr_ityp == TRITYP_STOCK)
{
      __msg(
       "   stock sh open %.lf gain %.2lf sh closed  %.2lf rlz gain %.2lf\n",
       -etrp->tr_quant,
       bsip->bas_all_unrlz_gain - bsip->bas_op_opt_unrlz_gain, 
       bsip->bas_rlz_traded_shares,
       bsip->bas_rlzgain_tot - bsip->bas_opt_rlzgain_tot);
}
// ====
    }
   if (bsip->bas_all_unrlz_gain != 0)
    {
      __msg("   open investment total (stk/fut/opt longs) %.2lf\n", 
       bsip->bas_investment_tot);
    } 
    
   if (bsip->bas_rlzgain_tot != 0)
    {
     bld_mth_tab_str(mthtotstr, &(bsip->bas_mth_rlzgain[0])); 
     __msg("RLZ STK and OPTS PER MTH %s\n", mthtotstr);
     } 
   
   if (bsip->bas_has_options)
    {
     __msg("OPT rlz gain %.2lf unrlz gain %.2lf\n",
      bsip->bas_opt_rlzgain_tot, bsip->bas_op_opt_unrlz_gain);
     if (bsip->bas_op_opt_unrlz_gain != 0)
      {
       __msg("  %0ld open POT income %.2lf\n",
        bsip->bas_open_opt_num,  bsip->bas_opt_pot_income);
      } 
     if (bsip->bas_opt_rlzgain_tot != 0)
      {
       bld_mth_tab_str(mthtotstr, &(bsip->bas_opt_mth_rlzgain[0])); 
       __msg("RLZ PER MTH OPT %s\n", mthtotstr);
      }
    }
   if (etrp->tr_ityp == TRITYP_STOCK)
    {
     /* will not be last div is tot divs fld 0 */
     if (bsip->ytd_tot_divs != 0)
       {
        if (etrp->tdy_pseudo_cl)
         {
          __dt_to_string(s1, &(bsip->bas_last_div_pay_dt));
          __msg(
           "   TOT DIVS %.2lf late wk div %.2lf (%.2lf) rate %.2lf%% on %s\n",
           bsip->ytd_tot_divs, bsip->bas_ldiv_persh,
           fabs(bsip->bas_ldiv_persh*etrp->tr_quant),
           100.0*((52.0*bsip->bas_ldiv_persh)/fabs(etrp->tr_price)), s1); 
          bld_mth_tab_str(mthdivstr, &(bsip->mth_divs[0]));
          __msg("PER MTH: %s\n", mthdivstr);
        }
       else
        {
         bld_mth_tab_str(mthdivstr, &(bsip->mth_divs[0])); 
          __msg("   TOT DIVS %.2lf\nPER MTH: %s\n", bsip->ytd_tot_divs, 
           mthdivstr);
         }
       }
    }
  }
}

/*
 * print mth div tab
 */
static char * bld_mth_tab_str(char *s, double *mtab)
{
 int32 mi;
 char s1[RECLEN], s2[RECLEN];
 
 strcpy(s, "");
 for (mi = 1; mi <= __cur_mth_num; mi++)
  {
   if (mtab[mi] != 0.0)
    {
     sprintf(s1, "\n  %s=%.2lf", __mth_num_to_mthabrv(s2,
      mi), mtab[mi]);
     strcat(s, s1); 
    }
  }
 if (s[0] == '\0') strcpy(s, "<EMPTY>");
 return(s);
}

/*
 * get date nearest before passed date
 * compared to today open
 * 
 * SJM 07-12-25 assume sip trans sort in trade date order
 */
static char *get_recent_op_dt(char *s, int32 cl_tri,
 struct symndx_t *sip) 
{
 int32 tri, dy, mth;
 struct trans_t *trp, *trp2;
 char codch;

 trp = __trantab[cl_tri];
 mth = trp->tdate.month;
 dy = trp->tdate.day;
 strcpy(s, "");
 for (tri = cl_tri - 1; tri >= sip->tr_bi; tri--)
  {
   trp2 = __trantab[tri];
   if (trp2->tdy_pseudo_cl) continue; 

   codch = __cod_opcl_ch(trp2->tr_code);
   if (codch != 'O') continue;
   /* can be same day */
   if (trp2->tdate.month > mth) __misc_terr(__FILE__, __LINE__);
   if (trp2->tdate.month == mth && trp2->tdate.day > dy)
    __misc_terr(__FILE__, __LINE__);
   /* can have open and close on same day */
   sprintf(s, "%02d/%02d", trp2->tdate.month, trp2->tdate.day);
   return(s);
  }
 strcpy(s, "<NONE>");
 return(s);
}

/*
 * for end pseudo cl get date of last cl before that if there is one
 * this works because starting one before possible last pseudo cl
 */
static char *get_recent_cl_dt(char *s, int32 tri, struct symndx_t *sip) 
{
 int32 tri2, mth, dy;
 struct trans_t *trp, *trp2;
 char codch;

 trp = __trantab[tri];
 mth = trp->tdate.month; 
 dy = trp->tdate.day; 
 /* tri will be the pseudo cl really */
 for (tri2 = tri - 1; tri2 >= sip->tr_bi; tri2--)
  {
   trp2 = __trantab[tri2];
   codch = __cod_opcl_ch(trp2->tr_code);
   if (codch != 'C') continue;
   /* can be same day */
   if (trp2->tdate.month > mth) __misc_terr(__FILE__, __LINE__);
   if (trp2->tdate.month == mth && trp2->tdate.day > dy)
    __misc_terr(__FILE__, __LINE__);
   sprintf(s, "%02d/%02d", trp2->tdate.month, trp2->tdate.day);
   return(s);
  }
 strcpy(s, "<NONE>");
 return(s);
} 

/*
 * acru dividends are like int and fees so print all together
 */
static void write_all_stk_acru_divs(void)
{
 int32 si, potri; 
 struct symndx_t *sip;
 struct trans_t *xdtrp;
 char s1[RECLEN], s2[RECLEN];

 __msg(
  "\n>>> CURRENT ACRUED unpaid dividends (sometimes ib pays day late):\n");
 __tot_open_acru_divs = 0;
 for (si = 0; si <= __last_symndxi; si++)
  {
   sip = __symndx[si];
   if (sip->open_stk_acru_div > 0)
    {
     potri = __fnd_1st_unpaired_acru_trans(sip->ndxsnamp);
     /* better be an open on if open acru divs non zero */
     if (potri == -1) __misc_terr(__FILE__, __LINE__);
     /* need acru div Po record to get price */
     xdtrp = __trantab[potri];
     __dt_to_string(s1, &(sip->op_xdiv_dt));
     __dt_to_string(s2, &(sip->op_div_pay_dt));
     __msg("   %s accrued xdiv %.2lf dt %s will be pd %s amt %.2lf\n",
      sip->ndxsnamp, xdtrp->tr_price, s1, s2, sip->open_stk_acru_div); 
     __tot_open_acru_divs += sip->open_stk_acru_div;
    }
  }
 __msg("    TOTAL CURRENT ACRUED: %.2lf\n", __tot_open_acru_divs);
}

/*
 * go thlu tran tab and clac and write fees and interest but not divs
 * for things not connected to symbols
 */
static void write_fee_and_int_totals(void)
{
 int32 tri;
 double com_tot, tax_tot_usd, tax_tot_cad, fee_tot; 
 double usd_int_cred_tot, usd_int_deb_tot, cad_int_cred_tot, cad_int_deb_tot;
 struct trans_t *trp;

 /* first calc total commissions - will be minus, i.e. a cost */
 for (com_tot = 0.0, tri = 0; tri <= __last_trani; tri++)
  {
   trp = __trantab[tri];
   if (trp->tr_typ == TRTYP_TRADE)
    {
     com_tot += trp->tr_comm;
    }
  }
 __msg(">>> Total YTD commissions %.2lf\n", com_tot);
 __ytd_tot_debits += com_tot;

 /* calc tax debits - Cdn and ??? */
 tax_tot_usd = tax_tot_cad = 0.0;
 for (tri = 0; tri <= __last_trani; tri++)
  {
   trp = __trantab[tri];
   if (trp->tr_typ == TRTYP_TAX)
    {
     if (trp->tr_ityp != TRITYP_DEBIT) __misc_terr(__FILE__, __LINE__);
     if (trp->cur_typ == CUR_USD) tax_tot_usd += trp->tr_amount;
     else if (trp->cur_typ == CUR_CAD) tax_tot_cad += trp->tr_amount;
     else __misc_terr(__FILE__, __LINE__);
    }
  }
 __msg(">>> Total Tax Withheld USD: %.2lf CAD: %.2lf\n", 
  tax_tot_usd, tax_tot_cad);
  __ytd_tot_debits += tax_tot_usd + tax_tot_cad;
 

 /* total fees - think always in USd */
 for (fee_tot = 0.0, tri = 0; tri <= __last_trani; tri++)
  {
   trp = __trantab[tri];
   if (trp->tr_typ == TRTYP_FEE)
    {
     /* DBG remove --- */
     if (trp->cur_typ != CUR_USD) __misc_terr(__FILE__, __LINE__);
     /* --- */
     fee_tot += trp->tr_amount;
    }
  }
 __msg(">>> Total YTD data fees %.2lf\n", fee_tot);
 __ytd_tot_debits -= fee_tot;

 /* interest credit for paid int on balance, debit or stock borrows */
 usd_int_cred_tot = usd_int_deb_tot = 0;
 cad_int_cred_tot = cad_int_deb_tot = 0.0;
 for (tri = 0; tri <= __last_trani; tri++)
  {
   trp = __trantab[tri];
   if (trp->tr_typ == TRTYP_INTEREST)
    {
     if (trp->cur_typ == CUR_USD)
      {
       if (trp->tr_ityp == TRITYP_CREDIT)
        usd_int_cred_tot += trp->tr_amount;
       else if (trp->tr_ityp == TRITYP_DEBIT)
         usd_int_deb_tot += trp->tr_amount;
       else __misc_terr(__FILE__, __LINE__);
      }
     else if (trp->cur_typ == CUR_CAD)
      {
       if (trp->tr_ityp == TRITYP_CREDIT)
        cad_int_cred_tot += trp->tr_amount;
       else if (trp->tr_ityp == TRITYP_DEBIT)
        cad_int_deb_tot += trp->tr_amount;
       else __misc_terr(__FILE__, __LINE__);
      }
     else __misc_terr(__FILE__, __LINE__);
    }
  }
 __msg(">>> Int USD cred %.2lf deb %.2lf CAD cred %.2lf deb %.2lf\n",
  usd_int_cred_tot, usd_int_deb_tot, cad_int_cred_tot,
  cad_int_deb_tot);
 /* SJM 08-30-25 - I do not use foreign currencies could convert */
 /* to your base here */
 __ytd_tot_int = usd_int_cred_tot - usd_int_deb_tot
  + cad_int_cred_tot - cad_int_deb_tot;
 __ytd_tot_debits -= usd_int_deb_tot - cad_int_deb_tot;
}

/*
 * ROUTINES TO CALC VARIOUS SIP TOTALS
 */

/*
 * calc tot of all realized gain (option, fut option and futures too)
 */
static void calc_various_totals()
{
 int32 si, mi;
 struct symndx_t *sip;
 struct trans_t *etrp;

 __ytd_open_gain = 0;
 __ytd_open_stk_gain = 0;
 __ytd_open_fut_gain = 0; 
 __ytd_open_opt_gain = 0;
 __ytd_open_futopt_gain = 0; 
 __tot_opt_pot_income = 0;
 __tot_futopt_pot_income = 0;

 __tot_ytd_rlz_gain = 0;
 for (mi = 0; mi <= 12; mi++) __mth_tot_rlz_gain[mi] = 0;
 __tot_stk_rlz_gain = 0;
 for (mi = 0; mi <= 12; mi++) __mth_stk_rlz_gain[mi] = 0;
 __tot_opt_rlz_gain = 0;
 for (mi = 0; mi <= 12; mi++) __mth_opt_rlz_gain[mi] = 0;
 __tot_fut_rlz_gain = 0; 
 for (mi = 0; mi <= 12; mi++) __mth_fut_rlz_gain[mi] = 0;
 __tot_futopt_rlz_gain = 0; 
 for (mi = 0; mi <= 12; mi++) __mth_futopt_rlz_gain[mi] = 0;

 __tot_tdy_net_val = 0;
 __tot_tdy_gross_val = 0;

 /* SJM 08-20-25 - these are for every sym not just bas syms */
 for (si = 0; si <= __last_symndxi; si++)
  {
   sip = __symndx[si];
   __ytd_open_gain += sip->unrlz_gain;
   __tot_ytd_rlz_gain += sip->rlzgain_tot;
   for (mi = 1; mi <= __cur_mth_num; mi++)
    {
     __mth_tot_rlz_gain[mi] += sip->mth_rlzgain[mi];
    }
   
   etrp = __trantab[sip->tr_ei];
   if (etrp->tr_ityp == TRITYP_STOCK)
    {
    __ytd_open_stk_gain += sip->unrlz_gain;
     __tot_stk_rlz_gain += sip->rlzgain_tot;
     for (mi = 1; mi <= __cur_mth_num; mi++)
      {
       __mth_stk_rlz_gain[mi] += sip->mth_rlzgain[mi];
      }
    }
   if (etrp->tr_ityp == TRITYP_FUT)
    {
     __ytd_open_fut_gain += sip->unrlz_gain;
     __tot_fut_rlz_gain += sip->rlzgain_tot;
     for (mi = 1; mi <= __cur_mth_num; mi++)
      {
       __mth_fut_rlz_gain[mi] += sip->mth_rlzgain[mi];
      }
    }
   if (etrp->tr_ityp == TRITYP_OPT)
    {
     __ytd_open_opt_gain += sip->unrlz_gain;
    __tot_opt_rlz_gain += sip->rlzgain_tot;
     for (mi = 1; mi <= __cur_mth_num; mi++)
      {
       __mth_opt_rlz_gain[mi] += sip->mth_rlzgain[mi];
      }
     __tot_opt_pot_income += sip->opt_pot_income; 
    }
   if (etrp->tr_ityp == TRITYP_FUTOPT)
    {
     __ytd_open_futopt_gain += sip->unrlz_gain;
    __tot_futopt_rlz_gain += sip->rlzgain_tot;
     for (mi = 1; mi <= __cur_mth_num; mi++)
      {
       __mth_futopt_rlz_gain[mi] += sip->mth_rlzgain[mi];
      }
     __tot_futopt_pot_income += sip->opt_pot_income; 
    }
  }
 /* calc the open pos dollar totals */
 __tot_tdy_net_val = 0;
 __tot_tdy_gross_val = 0;
 for (si = 0; si <= __last_symndxi; si++)
  {
   sip = __symndx[si];
   etrp = __trantab[sip->tr_ei];
   if (etrp->tdy_pseudo_cl)
    {
     __tot_tdy_gross_val += etrp->tr_tdy_closepr*etrp->tr_quant;
     if (etrp->is_buy)
      {
       /* pseudo close short */
       __tot_tdy_net_val -= etrp->tr_tdy_closepr*etrp->tr_quant;
      }
     else
      {
       /* pseudo close long */
       __tot_tdy_net_val += etrp->tr_tdy_closepr*etrp->tr_quant;
      }
    }
  }
}
