00001 #include <stdexcept>
00002 #include <iostream>
00003 #include "NewDateTime.h"
00004
00005 using namespace std;
00006
00007 NEWDATETIMEPTR const long mydate_csum[12]={0,31,59,90,120,151,181,212,243,273,304,334};
00008 NEWDATETIMEPTR const long mydate_mlength[12]={31,28,31,30,31,30,31,31,30,31,30,31};
00009
00010 NEWDATETIMEPTR const double days_per_year = (400.0*365+100-3)/400.0;
00011 NEWDATETIMEPTR const double inv_days_per_year = 400.0/(400.0*365+100-3);
00012
00013 NEWDATETIMEPTR char *month_list[12] = {
00014 "JAN",
00015 "FEB",
00016 "MAR",
00017 "APR",
00018 "MAY",
00019 "JUN",
00020 "JUL",
00021 "AUG",
00022 "SEP",
00023 "OCT",
00024 "NOV",
00025 "DEC"
00026 };
00027
00028 NEWDATETIMEPTR char *commodity_month_list[12] = {
00029 "F",
00030 "G",
00031 "H",
00032 "J",
00033 "K",
00034 "M",
00035 "N",
00036 "Q",
00037 "U",
00038 "V",
00039 "X",
00040 "Z"
00041 };
00042
00043 NEWDATETIMEFNC int STDCALL check_date_format( long date) {
00044 long cc, mm, dd;
00045
00046
00047 if (date < 0) {
00048 return 5;
00049 }
00050
00051 cc = date / 1000000;
00052
00053 mm = (date / 100 ) % 100;
00054 dd = date % 100;
00055
00056 if (cc!=0 && (cc < 12 || cc > 22)) {
00057 return 1;
00058 }
00059 if (mm < 1 || mm > 12) {
00060 return 2;
00061 }
00062 if (dd < 1 || dd > 31) {
00063 return 3;
00064 }
00065
00066 return 0;
00067 }
00068
00069 NEWDATETIMEFNC int STDCALL check_month_format( long date)
00070 {
00071 long cc, mm;
00072
00073 if (date < 0) return 5;
00074
00075 cc = date / 10000;
00076 mm = date % 100;
00077
00078 if (cc!=0 && (cc < 12 || cc > 22)) return 1;
00079 if (mm < 1 || mm > 12) return 2;
00080
00081 return 0;
00082 }
00083
00084 NEWDATETIMEFNC long STDCALL serial_month( long month)
00085 {
00086 long cc, yy, mm, serial;
00087
00088 if ((cc=check_month_format( month))!=0) {
00089 throw domain_error( "month has bad format");
00090 }
00091
00092 cc = month / 10000;
00093 if (cc==0) {
00094 cc = 19;
00095 }
00096
00097 yy = (month / 100) % 100;
00098
00099 mm = month % 100;
00100
00101 serial = (cc - 19) * 1200 + yy * 12 + mm-1;
00102
00103 return serial;
00104 }
00105
00106 NEWDATETIMEFNC long STDCALL inv_serial_month( long serial)
00107 {
00108 long month, cc, yy, mm;
00109
00110 if (serial >= 0)
00111 {
00112 cc = serial / 1200 + 19;
00113 }
00114 else
00115 {
00116 cc = serial / 1200 + 18;
00117 }
00118 serial -= (cc - 19) * 1200;
00119
00120 yy = serial / 12;
00121 serial -= yy * 12;
00122
00123 mm = serial+1;
00124
00125 month = cc * 10000 + yy * 100 + mm;
00126
00127 return month;
00128 }
00129
00130
00131 NEWDATETIMEFNC bool STDCALL is_leap( int CCYY) {
00132 return (CCYY%4 == 0 && (CCYY%400 == 0 || CCYY%100 != 0));
00133 }
00134
00139 NEWDATETIMEFNC int STDCALL cbot_ag_option_expiration_algorithm( int ccyymm) {
00140 ccyymm = inv_serial_month( serial_month( ccyymm)-1);
00141 int mm = ccyymm % 100;
00142 int ccyy = ccyymm / 100;
00143 int month_length;
00144
00145 if (mm > 12 || mm < 1) throw domain_error( "invalid month passed to cbot_ag_option_expiration_algorithm");
00146 month_length = mydate_mlength[mm-1];
00147 if (is_leap(ccyy)) month_length++;
00148
00149 int dy = month_length;
00150 int ccyymmdd = ccyymm * 100 + dy;
00151 int wkdy;
00152
00153 int num_business_days=0;
00154 for (;;) {
00155 wkdy = week_day( ccyymmdd);
00156 if (wkdy >=1 && wkdy <=5) num_business_days++;
00157 if (num_business_days == 2) break;
00158 ccyymmdd--;
00159 }
00160
00161 int shift = wkdy-5;
00162 if (shift <= 0) shift += 7;
00163 ccyymmdd -= shift;
00164
00165 return ccyymmdd;
00166 }
00167
00172 NEWDATETIMEFNC int STDCALL cbot_ag_option_expiration2( int ccyy, char month_code) {
00173 int i;
00174 for (i=0; i<12; i++) {
00175 if (commodity_month_list[i][0] == month_code) {
00176 break;
00177 }
00178 }
00179 if (i==12) {
00180 throw domain_error( "month_code not recognized");
00181 }
00182 i++;
00183 int ccyymm = ccyy * 100 + i;
00184 return cbot_ag_option_expiration( ccyymm);
00185 }
00186
00187
00189 NEWDATETIMEFNC int STDCALL cbot_ag_option_expiration( int ccyymm) {
00190 int i, diff;
00191
00192 for (i = 0; all_expirations[i].ccyymm != 0; i++) {
00193 if (all_expirations[i].ccyymm == ccyymm) {
00194 diff = day_diff( ccyymm*100 + 1, all_expirations[i].ccyymmdd);
00195 if (diff < 0 || diff > 30) {
00196 cerr << "warning bad data in lookup table for ccyymm = "
00197 << ccyymm
00198 << " and ccyymmdd = "
00199 << all_expirations[i].ccyymmdd
00200 << "diff = "
00201 << diff
00202 << endl;
00203 return cbot_ag_option_expiration_algorithm( ccyymm);
00204 }
00205
00206 return all_expirations[i].ccyymmdd;
00207 }
00208 }
00209
00210 return cbot_ag_option_expiration_algorithm( ccyymm);
00211 }
00212