Converting an Index to a UCITS III compliant constrained weights index

The UCITS III directive imposes certain investment limits to funds originating in member states
of the European Union. This article describes this in ore detail and presents a software solution which will convert an existing non-compliant index into a UCITS III constrained weights compliant one.

In a nutshell - with respect to constrained weights - UCITS III states that any single entity in
an index should be no more than 10% of the overall weight of the index. Further, the total weight
of all entities with a weight > 5% should be no more that 40% of the total weight of the index.

Note that in this context an index "entity" can consist of more than one index member if the members belong to the same "line".

In practice, the above constraints would lead to constant rebalancing and turnover of the index
therefore most leading index providers typically use a 10% buffer on the above constraints to
minimize this. In other words in practice the constraints become:-

No individual entity > 9%

and

The sum of the weights of all entities >4.5%  must be <=36% of the total index weight.

Given the above conditions we see immediately that the source index we wish to convert
to UCITS III compliance must have at least 19 members. If there are only 18 entities
typically the 10% buffer mentioned above will be reduced to , say , 9%. 17 entities will
reduce it to 4% and 16 members to 0%.

Indcies containing fewer than 16 entities cannot be converted to a UCITS III compliant index.

Methodology
============

The process of creating a UCITS III compliant index is esentially iterative. We try all valid
combinations of weights within the UCITS guidelines and test each combination for UCITS III compliance.
For large indices its likely that there will be several hundered if not thousands of combinations
that will be UCITS III compliant. In order to choose which one becomes thee UCITS III index we
compare it to the original index and determine its tracking error. The one with the lowest
tracking error becomes our new UCITS III compliant index.

In programming terms we logically divide our orginal index into 3 pivot points after sorting it
by index weight - records 1 to N.

CAP PIVOT - points to the lowest entity with weight = 9%
HIGH PIVOT - points to the highest entity with weight = 4.5%
LOW PIVOT - ito the lowest entity with weight = 4.5%

The entities between the CAP PIVOT point and HIGH PIVOT point are designated HIGH_CAPS.
The entities below the LOW PIVOT point are designated LOW_CAPS.

The weights of the entities between and including index entity 1 and the CAP PIVOT
and between the HIGH PIVOT and LOW PIVOT points are fixed until the next iteration.

By setting the three pivot points, some weights are then fixed at the 9% and 36% limits. Allocation
of the weight differences between the original index and the capped weights is applied
on a proportional basis to the LOW_CAPS and HIGH_CAPS. When this has been done we check for
the 36% limit again. Any overweight in this must be removed proportionally from the HIGH_CAPS and
allocated to the LOW_CAPS. Finally a check is made that no further breaches have occurred. If
they have we discard the solution and we move to the next iteration. If not save this solution
and move to the next iteration. At the end, check all saved solutions against the original index.

The solution with the lowest tracking error becomes our UCITS III compliant index.

Software solution

The software is written in JAVA and was written on a PC using the Eclipse Luna IDE. The target system is an OpenVMS box running an Oracle RDBMS. Database connection and IP details in the code have been changed to protect the innocent. Also there are several references to database tables used that you wont have on your system. It should be reasonably clear what these tables are used for.

Record.java

package ucits;

public class Record {
private String smnem;
private double mcap;
private double wgt;
private double fixed_wgt;
private double factor;
private double fixing;
private double allocated_wgt;
private double final_wgt = 0;
private char id;

// Constructor
public Record(String smnem2, double mcap2) {
smnem = smnem2;
mcap = mcap2;
wgt = 0.0;
fixed_wgt = 0.0;
allocated_wgt = 0.0;
final_wgt = 0.0;
factor = 1;
fixing = 0;
id = 'I';
}

public Record() {
}

public String GetSmnem() {
return smnem;
}

public double GetWgt() {
return wgt;
}

public double GetMcap() {
return mcap;
}

public char GetId() {
return id;
}

public double GetFixing() {
return fixing;
}

public double GetFactor() {
return factor;
}

public double GetFixedWgt() {
return fixed_wgt;
}

public double GetAllocWgt() {
return allocated_wgt;
}

public double GetFinalWgt()
{
return final_wgt;
}

public void SetId(char sid) {
id = sid;
}

public void SetWgt(double swgt) {
wgt = swgt;
}

public void SetFixing(double sfixing) {
fixing = sfixing;

}

public void SetFactor(double sfactor) {
factor = sfactor;
}

public void SetFixedWgt(double snewwgt) {
fixed_wgt = snewwgt;
}

public void SetAllocWgt(double salloc) {
allocated_wgt = salloc;
}

public void SetFinalWgt(double sfinal)
{
final_wgt = sfinal;
}

public void SetSmnem(String ssmnem)
{
smnem = ssmnem;
}

public void SetMcap(double smcap)
{
mcap = smcap;
}

RecordGroup.java

package ucits;

import java.util.ArrayList;

public class RecordGroup {

private ArrayList indexList;
private double thetaSquared;

public RecordGroup(ArrayList recList,double theta) {
thetaSquared = theta;
indexList = recList;
}
public double getThetaSquared() {
return thetaSquared;
}
public void setThetaSquared(double thetaSquared) {
this.thetaSquared = thetaSquared;
}
public ArrayList getIndexList() {
return indexList;
}
public void setIndexList(ArrayList sIndex) {
indexList = sIndex;
}
}

ucits.java

package ucits;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

public class ucits {

public static final String DBURL = "jdbc:oracle:thin:@your_ip:your_dbname";
public static final String DBUSER = "your_username";
public static final String DBPASS = ""your_passwword
public static final int CCL = 36;
public static final double CT = 4.5;
public static final int ICL = 9;
public static String errorMessage ="";
public static String source_pmnem = "";
public static String source_ic_class = "";
public static String ucits_pmnem = "";
public static String ucits_ic_class = "";
public static String ic_class ="";
public static String area_mnem = "";
public static String start_date = "";
public static String p_enddate;
public static int rowCount = 0;
public static double mcap_tot = 0.0;
public static int  index=-1;

public static boolean isValidDate(String date)
{
// set date format, this can be changed to whatever format
// you want, MM-dd-yyyy, MM.dd.yyyy, dd.MM.yyyy etc.
// http://java.sun.com/j2se/1.4.2/docs/api/index.html

SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy");

sdf.setLenient(false); // strict checking in force

// declare and initialize testDate variable, this is what will hold
// our converted string

Date testDate = null;

// we will now try to parse the string into date form
try {
testDate = sdf.parse(date);
//System.out.println("testDate =  : "+testDate);
}

// if the format of the string provided doesn't match the format we
// declared in SimpleDateFormat() we will get an exception

catch (ParseException e) {

return false;
}

return true;

}

// This is where we retrieve our main data set and store into an array of Record types
// This data structure will be our initial "portfolio" which we then process later to see if we
// can construct a UCITS III compliant portfolio from it.
//
// We also get some other data that is used later on in the program.

public static void get_data(String s,String source_pmnem,ArrayList recList) throws SQLException {

String smnem; // Index entity mnemonic
double mcap;  // Index market cap
int nr_rows = 0;

//        String cbuf;
//        System.out.print("Enter required date in dd-mmm-yyyy format: ");
//

if(!isValidDate(s)) {
System.out.println("Date entered is invalid");
System.exit(0);
}
else {

// build SQL query
// Obviously these details are specific to my system but essentially you want a list
// of index members and their market caps ordered by market cap
String q = "";

q += "select  i.s_parent,  sum(capel.market_cap_in_currency_qt2(i.s_mnem,to_date('" + s + "')" ;
q += "-1,to_date('" + s + "'),pc.c_mnem,ps.shs_source)/ic_factor) ffmc ";
q += "from p_curr pc, p_shs_source ps, special_areas a, indx_class i, p_foliolu p ";
q += "where   pc.c_startdate <= to_date('" + s + "') ";
q += "and     (ps.shs_enddate is null or ps.shs_enddate >= to_date('" + s + "')) ";
q += "and     (pc.c_enddate is null or pc.c_enddate >= to_date('" + s + "')) ";
q += "and     (i.ic_enddate is null or i.ic_enddate >= to_date('" + s + "')) ";
q += "and     i.ic_startdate <= to_date('" + s + "') ";
q += "and     ps.shs_startdate <= to_date('" + s + "') ";
q += "and     pc.p_mnem = p.p_mnem ";
q += "and     ps.p_mnem = p.p_mnem ";
q += "and     a.mrkt_mnem = i.ic_mrkt and  a.area_mnem = nvl(p.area_mnem,'WORLD') ";
q += "and     i.ic_class = p.ic_class and  (i.ic_grp = p.ic_grp or p.ic_grp is null) ";
q += "and     (i.ic_sec = p.ic_sec or p.ic_sec is null)    and (i.ic_sub = p.ic_sub or p.ic_sub is null) ";
q += "and     p.p_mnem = '" + source_pmnem + "' group by i.s_parent order by 2 desc";

//System.out.println("query = " + q);

DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());

// Connect to Oracle Database

Connection con = DriverManager.getConnection(DBURL, DBUSER, DBPASS);

Statement statement = con.createStatement();

ResultSet rs = statement.executeQuery(q);

while (rs.next()) {

smnem = rs.getString(1);
mcap = rs.getDouble(2);

Record Rec = new Record(smnem,mcap);

mcap_tot = mcap_tot + mcap;

rowCount++;

}

if(rowCount > 0)
rs.close();
else
{
System.out.println("No data found ... exiting");
System.exit(0);
}

q = "";
q = "select ic_class from p_foliolu where p_mnem = upper('" + source_pmnem + "')";

rs=statement.executeQuery(q);

nr_rows = 0;

while(rs.next()) {

source_ic_class = rs.getString(1).toUpperCase();
nr_rows++;
}

if(nr_rows>0)
rs.close();
else if(nr_rows > 2)
{
System.out.println("More than 1 P_FOLIOLU record found for mnemonic " + source_pmnem + " ...exiting");
System.exit(0);

}

q="";
q = q + "select area_mnem,ic_class from p_foliolu where p_mnem = '" + ucits_pmnem + "'";
rs=statement.executeQuery(q);

nr_rows = 0;
while(rs.next()) {
area_mnem = rs.getString(1).toUpperCase();
ic_class = rs.getString(2).toUpperCase();
nr_rows++;
}

if(nr_rows>0)
rs.close();
else if(nr_rows > 2)
{
System.out.println("More than 1 P_FOLIOLU record found for mnemonic " + ucits_pmnem + " ...exiting");
System.exit(0);

}

if (!(ic_class == null || ic_class.trim().equals("")))
{
ucits_ic_class = ic_class;
}

q="";
q = q + "select to_date('" + start_date +"','DD-MON-RR')-decode(to_char(to_date('" + start_date + "','DD-MON-RR'),'DY'),'MON',3,'SUN',2,1) from dual";
rs=statement.executeQuery(q);

nr_rows = 0;
while(rs.next()) {

p_enddate = rs.getString(1).substring(0, 10);
nr_rows++;
}

if(nr_rows>0)
rs.close();

statement.close();
con.close();

System.out.println("Portfolio records retrieved  = " + rowCount);

if (rowCount > 0)
{
System.out.println("Original pfolio");
System.out.println("---------------");
System.out.println("SMNEM\t| Weight");
System.out.println("-----\t|-------");
// Set initial weights based on mcap
for (int i = 0; i < recList.size(); i++) {

Record rec = (Record)recList.get(i);
rec.SetWgt ((rec.GetMcap() / mcap_tot)*100);
rec.SetFixedWgt(rec.GetWgt());
System.out.println(rec.GetSmnem() + "\t|" + rec.GetWgt());

}
System.out.println();
}
}

}

// Checks a portfolio for UCITS compliance
// Type = I indicates we just want to check initial pfolio
// for UCITS compliance  i.e no need to calculate theta.
// Returns < 0  if pfolio is not UCITS compliance

public static double check_index(ArrayList recList,char type)
{
double ul = 0;
double tot = 0;
double wgt = 0.0;
double theta = 0;
double orig_wgt = 0.0;
double final_wgt = 0.0;

for (int i = 0; i < recList.size(); i++)
{
Record rec = (Record)recList.get(i);

char id = rec.GetId();

orig_wgt = rec.GetWgt();
final_wgt = rec.GetFinalWgt();

if(type == 'I')
wgt = orig_wgt;
else
wgt = final_wgt;

tot+=wgt;

// max weight of any one stock <= 9
if(wgt > ICL)
{
return -1;
}

// No short positions
if(wgt < 0)
{
return -2;
}

if (wgt > CT)   // > 4.5%
{
ul += ul;
};

if(id == '9' && wgt != ICL)
return- 4;
if(id == 'N' && wgt != CT)
return -5;
if(id == 'H' && wgt <= CT)
return -6;

// theta is a measure of how different the new portfolio is from our original
// We this to be a minimum

theta = theta + (final_wgt-orig_wgt)*(final_wgt-orig_wgt);

}

// the sum of all weights > 4.5 must be <= CCL
if (ul > CCL || (tot > 100.0001 || tot < 99.9999) )
{
return -3;
}

if(type == 'I')
return 0;

return theta;
}

// Print out a portfolio
public static void print_index(ArrayList recList)
{
System.out.println("SMNEM\t|Original Weight\t|UCITS Weight\t|UCITS factor");
System.out.println("-----\t|---------------\t|------------\t|------------");

for (int i = 0; i < recList.size(); i++) {

Record rec=(Record)recList.get(i);

System.out.println(rec.GetSmnem() +"\t|" + rec.GetWgt() + "\t|" + rec.GetFinalWgt() + "\t|" + rec.GetWgt()/rec.GetFinalWgt() );

}
}

//
// This is the main procedure to calculate a UCITS III compliant pfolio.
// Basically we set 3 pivot points -  CAP Pivot (wgt = 9%), HIGH Pivot (wgt = 4.5%)
// and LOW pivot (wgts < 4.5%) - on the array of our original pfolio records. Starting at record 1
// we then iterate through all valid combinations of the above pivot points, adjusting the
// pfolio weights to create a new synthetic pfolio. At the end of each iteration we
// test the resulting new pfolio to see whether its UCITS compliant or not.
// If not we do the next iteration, if yes we store the new pfolio and go on to the
// next iteration. When all itearations are complete we cycle through any saved UCITS
// compliant pfolios and calculate which one has the lowest tracking error between it
// and the original non-compliant pfolio. The lowest becomes our new UCITS compliant pfolio
//
public static void iterate_weights(ArrayList recList,ArrayList indexList) {

int cap_pivot = 0;
int high_pivot = 0;
int low_pivot = 0;
int n = recList.size();

int k1 = 0; // nr caps = 9
int k2 = 0; // nr high caps ( > 4.5 & < 9 )

if(check_index(recList,'I') < 0)
{
for(k1=0;k1<=4;k1++)
{
cap_pivot = k1;

for(k2=0;k2<=(8-2*k1);k2++)
{
if(cap_pivot == 0)
{
high_pivot = 0;
}
else
{
high_pivot = cap_pivot+k2+1;
}

for (int i=1;i<=n;i++)
{

double hilo_caps = 0;
double hi_caps = 0;
double lo_caps = 0;
double nine_caps = 0.0;
double sum_fixed = 0;
double sum_ccl = 0.0;

double factor = 0;
double lo_cap_factor = 0.0;
double hi_cap_factor = 0.0;

low_pivot = Math.max(i,high_pivot);

// Assign 9% weights
for (int l1 =1;l1<=cap_pivot;l1++)
{
Record rec = (Record)recList.get(l1-1);
rec.SetFixedWgt(ICL);
rec.SetId('9');
}

// Assign high cap weights
for (int l2=cap_pivot+1;l2<high_pivot;l2++)
{
Record rec = (Record)recList.get(l2-1);
rec.SetFixedWgt(rec.GetWgt());
rec.SetId('H');
}

// Assign 4.5% weights
for (int l3=Math.max(high_pivot,1);l3<=low_pivot;l3++)
{
Record rec = (Record)recList.get(l3-1);
rec.SetFixedWgt(CT);
rec.SetId('N');
}

if(high_pivot == low_pivot)
{
for(int l4=low_pivot;l4<=n;l4++)
{
Record rec = (Record)recList.get(l4-1);
rec.SetFixedWgt(rec.GetWgt());
rec.SetId('L');
}
}
else
{
// Assign low caps
for(int l4=low_pivot+1;l4<=n;l4++)
{
Record rec = (Record)recList.get(l4-1);
rec.SetFixedWgt(rec.GetWgt());
rec.SetId('L');
}
}

// When we've got to here we have done 1 iteration of setting the CAP, HIGH and LOW pivots
// And we have set our fixed 4.5% and 9% weights if any.
// We now calculate the factor to be applied to any HIGH & LOW cap weights
// i.e the factor is applied to any wgts > 4.5 &&  < 9 or those < 4.5
//
// factor =  1+( (100-SUM(NEW WGTS))/SUM(HIGH/LOW CAPS))

for(int y=1;y<= n;y++)
{

Record rec4 = (Record)recList.get(y-1);

sum_fixed+=rec4.GetFixedWgt();

if(rec4.GetId() == 'L')
{

lo_caps += rec4.GetFixedWgt();
}
if(rec4.GetId() == 'H')
{

hi_caps += rec4.GetFixedWgt();
}

}

hilo_caps = lo_caps+hi_caps;

factor = 1 + ((100-sum_fixed)/hilo_caps);

// Next we apply this factor to all HIGH & LOW CAP fixed weights
// to give us a set of allocated weights

hi_caps = 0;
lo_caps = 0;
nine_caps = 0;

// In this loop we  apply our factor. Also check for CCL (36% threshold) being overweight and if it
// is we move the overweight
// portion from the high caps to the low caps

for (int t=1;t<= n;t++)
{

Record rec4 = (Record)recList.get(t-1);

if(rec4.GetId() == 'H' || rec4.GetId() == 'L')
{
rec4.SetAllocWgt(rec4.GetFixedWgt()*factor);
}
else
{
rec4.SetAllocWgt(rec4.GetFixedWgt());
}

rec4.SetFinalWgt(rec4.GetAllocWgt());

// Calculate some intermediate results for next step

if(rec4.GetId() == '9')
{
nine_caps += rec4.GetAllocWgt();
}
if(rec4.GetId() == 'L')
{

lo_caps += rec4.GetAllocWgt();
}
if(rec4.GetId() == 'H')
{

hi_caps += rec4.GetAllocWgt();
}

// Allocate any CCL (36% threshold) overweight to low caps
sum_ccl = hi_caps + nine_caps;

if (sum_ccl > CCL)
{
hi_cap_factor = 1 - (sum_ccl-CCL)/hi_caps;
lo_cap_factor = 1 + (sum_ccl-CCL)/lo_caps;

if(rec4.GetId() == 'H')
{
rec4.SetFinalWgt(rec4.GetAllocWgt()*hi_cap_factor);
}

if(rec4.GetId() == 'L')
{
rec4.SetFinalWgt(rec4.GetAllocWgt()*lo_cap_factor);
}
}

}

// Check pfolio for UCITS compliance ( returns > 0 if yes)
// If it is store it so we can check which one is optimal
double chk = check_index(recList,'F');
if( chk > 0 )
{
store_pfolios(recList,chk,indexList);
}
}
}
}
}
else
{
System.exit(0);
}

}

public void prompt() throws IOException
{

}

// Store UCITS pfolio in temp collection data structure
// We have to make a copy of the pfolio before storing as JAVA passes everything by REF
// This prevents subsequent changes affecting our collection of stored pfolios
public static void store_pfolios(ArrayList recList, double theta, ArrayList indexList) {

ArrayList recList2 = new ArrayList();

for (int x = 0 ; x < recList.size();x++)
{
Record rec5 = new Record();
Record rec6 = (Record)recList.get(x);

rec5.SetFactor(rec6.GetFactor());
rec5.SetFinalWgt(rec6.GetFinalWgt());
rec5.SetFixedWgt(rec6.GetFixedWgt());
rec5.SetAllocWgt(rec6.GetAllocWgt());
rec5.SetFixing(rec6.GetFixing());
rec5.SetId(rec6.GetId());
rec5.SetWgt(rec6.GetWgt());
rec5.SetSmnem(rec6.GetSmnem());
rec5.SetMcap(rec6.GetMcap());

}

RecordGroup rGroup = new RecordGroup(recList2, theta);
}

// Iterate through our stored list of UCITS compliant pfolios, calculate the
// optimal one and store its position in the data structure (index variable)
// and print it out.
public static void get_optimal_pfolio(ArrayList iList) {

ArrayList rList = new ArrayList();

double smallestTheta = 100000000.0;

index = -1;

for (int i=0;i< iList.size();i++)
{
RecordGroup rGroup =(RecordGroup)iList.get(i);

if(rGroup.getThetaSquared() < smallestTheta)
{
smallestTheta = rGroup.getThetaSquared();
rList = rGroup.getIndexList();
index = i;
//print_index(rList);
}
}

if(index == -1)
{
System.out.println("No UCITS compliant pfolio found");
return;
}

System.out.println("Smallest Theta = " + smallestTheta + ", Index = " + index);
System.out.println("Optimal UCITS compliant pfolio");
System.out.println("------------------------------");
print_index(rList);
}

// Insert our optimal pfolio into the database
//
public static void store_optimal_pfolio(int pos, ArrayList iList) throws SQLException
{

DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());

// Connect to Oracle Database

Connection con = DriverManager.getConnection(DBURL, DBUSER, DBPASS);

PreparedStatement preparedStatement = con.prepareStatement("delete from indx_class where ic_class = ? and ic_startdate >= to_date(?,'DD-MON-RR')");
preparedStatement.setString(1, ucits_ic_class);
preparedStatement.setString(2, start_date);

int deleteCount = preparedStatement.executeUpdate();

con.close();

RecordGroup rGroup =(RecordGroup)iList.get(pos);
ArrayList recs = rGroup.getIndexList();

con = DriverManager.getConnection(DBURL, DBUSER, DBPASS);

System.out.println();
System.out.println("Writing UCITS pfolio to the database");
System.out.println();
for(int i = 0;i< recs.size();i++)
{

Record pfolio = (Record)recs.get(i);
double orig_wgt = pfolio.GetWgt();
double new_wgt = pfolio.GetFinalWgt();
double pfactor = orig_wgt/new_wgt;
String smnem = pfolio.GetSmnem();

preparedStatement = con.prepareStatement
(
"insert into indx_class i1 (ic_class,ic_grp,ic_sec,ic_sub,ic_mrkt,s_mnem,s_parent,ic_startdate,ic_enddate,ic_factor,change_date) " +
"select ?,ic_grp,ic_sec,ic_sub,ic_mrkt,s_mnem,s_parent,to_date(?,'DD-MON-RR'),ic_enddate,?*ic_factor,sysdate " +
"from indx_class i2 where i2.ic_class = upper(?) and i2.ic_startdate <= to_date(?,'DD-MON-RR') " +
"and (i2.ic_enddate is null or i2.ic_enddate >= to_date(?,'DD-MON-RR')) " +
"and s_parent = ?"
);
preparedStatement.setString(1, ucits_ic_class);
preparedStatement.setString(2, start_date);
preparedStatement.setDouble(3, pfactor);
preparedStatement.setString(4, source_ic_class);
preparedStatement.setString(5, start_date);
preparedStatement.setString(6, start_date);
preparedStatement.setString(7, smnem);

int insertCount = preparedStatement.executeUpdate();

preparedStatement = con.prepareStatement
(
"update indx_class set ic_enddate = to_date(?,'YYYY-MM-DD') where ic_class = ? and ic_startdate <= to_date(?,'YYYY-MM-DD') " +
"and (ic_enddate is null or ic_enddate >=  to_date(?,'YYYY-MM-DD')) and s_parent = ? "

);
preparedStatement.setString(1, p_enddate);
preparedStatement.setString(2, ucits_ic_class);
preparedStatement.setString(3, p_enddate);
preparedStatement.setString(4, p_enddate);
preparedStatement.setString(5, smnem);

int updateCount = preparedStatement.executeUpdate();

System.out.println("Smnem:" + smnem + "\t|factor applied: " + pfactor);
}

con.close();

con = DriverManager.getConnection(DBURL, DBUSER, DBPASS);

// The below prepared statement should look something like this and is done to ensure any stocks
// that came out of the source index GLOBMIN in the latest rebalaance
// get their ic_enddate set properly in the new UCITS index
//
// set i.ic_enddate =
// (
//    select ic_enddate
//    from indx_class where ic_class = 'GL'
//    and ic_enddate is not null
//    and s_mnem = i.s_mnem
//    and trunc(ic_startdate) = trunc(i.ic_startdate)
// )
// where ic_class = '19'
// and ic_enddate is null
// and ic_startdate <= '19-jun-15'

System.out.println("Updating UCITS end dates for any stocks removed in latest rebalalance of source indx:" +source_ic_class);
preparedStatement = con.prepareStatement
(
"update indx_class i set i.ic_enddate = ( select ic_enddate from indx_class  where ic_class = ? " +
"and ic_enddate is not null and s_mnem = i.s_mnem and trunc(ic_startdate) = trunc(i.ic_startdate) ) " +
"where ic_class = ? and ic_enddate is null and ic_startdate <= to_date(?,'YYYY-MM-DD')"
);

preparedStatement.setString(1, source_ic_class);
preparedStatement.setString(2, ucits_ic_class );
preparedStatement.setString(3, p_enddate);

int updateCount = preparedStatement.executeUpdate();

con.close();
System.out.println("Nr ic_enddates updated = "+ updateCount);

}

public static void main(String[] args) throws SQLException, IOException {

ArrayList recList  = new ArrayList();
ArrayList indexList = new ArrayList();

if (args.length != 4) {
System.out.println("Usage: @ucits start_date(dd-mmm-yy) source_pmnem  ucits_ic_class ucits_pmnem");
System.out.println("  e.g. @ucits 22-mar-15 GLOBMIN UG GLOBMIU");
return;
}

start_date =args;
source_pmnem=args.toUpperCase();
ucits_ic_class=args.toUpperCase();
ucits_pmnem=args.toUpperCase();

System.out.println("Run-time parameters are - Date:" + args + "  Source pmnem:" + source_pmnem + "  UCITS ic_class:" + ucits_ic_class + "  UCITS pmnem:" + ucits_pmnem);

get_data(args,source_pmnem,recList);

iterate_weights(recList,indexList);

get_optimal_pfolio(indexList);

System.out.print("Write UCITS data to database? (Y/N): ");

if (s.equals("Y") || s.equals("y"))
store_optimal_pfolio(index,indexList);

System.out.println("Finished");
System.exit(0);
}
}

`​A selection of topics on IT and its application to finance. ​Send me your comments, questions ​or suggestions by clicking h​ere`
`elmama`