0

I am trying to build a logic for a Foreign currency calculator.

I have got below foreign currencies mapping and their rates given ( coming from application_input.properties ) :

EURUSD=1.2 
USDJPY=11.95 
AUDUSD=21.83 
CADUSD=2.87 
USDCNY=6.17 
GBPUSD=1.56 
NZDUSD=3.77 
EURCZK=2.60 
EURDKK=7.44 
EURNOK=8.66

If I have to find EUR to USD conversion then I got that.. as its given directly EUR - USD = 1.2
If I need DKK to EUR that is also given but by inverse .. i.e. 1/7.44
If I need AUD to CZK that can be found by linking (a Cross) AUD -> USD -> EUR ( Inverse of EURUSD ) -> CZK

I am trying to think through the logic ( In Java with any API ) but couldn't find as of now.

Can anyone help me here, please?

I tried to create a table(sheet) having mapping of all the currencies. So that I can visit that sheet and see how to find the link between the currencies. I was able to generate the Currencies having Direct rates/Inverse rates and stuck at generating links between cross currency rates.

Here is the code:

package com.nitin.fxcalculator;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;

import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;

/**
 * Hello world!
 *
 */
public class App {

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

     App app = new App();
     /*Scanner scanner = new Scanner(System. in); 
     String input = scanner.nextLine();

     String [] inputParams = input.split("\\s+");
     if(ifValidParams(inputParams) == false) {
         System.exit(1);
     }*/

     Properties propFile = app.loadInputFile();
     Set<String> currencies = findCurrencyAvailable(propFile);
     Map<String, Double> currencyRate = getCurrencyRates(propFile);
     System.out.println("Rates given - "+ currencyRate.size());
     System.out.println(currencyRate);
     generateCurrencyLink(currencies, currencyRate);

    }

    public static boolean ifValidParams(String [] inputParams) {
     if(inputParams.length != 4) {
         System.out.println("Incorrect no of arguments");
         return false;
     }
     if(!inputParams[2].equals("in")) {
         System.out.println("Invalid args at position - " + 3);
         return false;
     }
     return true;
    }


    /*************
     * 
     * @return
     * @throws IOException
     */
    public Properties loadInputFile() throws IOException {
     Properties      prop            = new Properties();
     InputStream     input           = null;

     ClassLoader classLoader = this.getClass().getClassLoader();
     File file = new File(classLoader.getResource("application_input.properties").getFile());

     input = new FileInputStream(file);
     prop.load(input);

     return prop;
    }

    /*******************************************
     * Read the input properties file 
     * where initial currencies and values
     * are given.
     * Determine the total currencies available
     * and return a set of those
     * @return
     * @throws IOException
     *******************************************/
    public static Set<String> findCurrencyAvailable(Properties prop) throws IOException {
     Set<String>   setOfCurrencies = new TreeSet<String>();

     for(Object setItem : prop.keySet()) {
         String key = (String)setItem;
         setOfCurrencies.add(key.substring(0, 3));
         setOfCurrencies.add(key.substring(3, 6));
     }

     return setOfCurrencies;
    }

    public static Map<String, Double> getCurrencyRates(Properties prop) {
     Map<String, Double> currencyRate = new HashMap<String, Double>();

     for(Entry<Object, Object> property : prop.entrySet()) {
         currencyRate.put((String)property.getKey(), Double.valueOf((String)property.getValue()));
     }

     return currencyRate;
    }

    public static void generateCurrencyLink(Set<String> currencies, Map<String, Double> currencyRate) throws IOException {
     FileOutputStream  file = new FileOutputStream (new File("C:\\temp.xls"));

     //Get the workbook instance for XLS file 
     HSSFWorkbook workbook = new HSSFWorkbook();

     //Get first sheet from the workbook
     HSSFSheet sheet = workbook.createSheet("sample");


        Row row = sheet.createRow(0);
        int cellnum = 1;
        for (String currency : currencies) {
            Cell cell = row.createCell(cellnum++);
            cell.setCellValue(currency);
        }

     int rowNum = 1;
     String key = null;
     String keyInverse = null;
     String value = null;
     for(int i = 0 ; i < currencies.size();i++) {
         row = sheet.createRow(rowNum);
         int cellNum = 0;
         for (int j = 0;j < currencies.size();j++) {
             Cell cell = null;
             if(cellNum == 0) {
                 cell = row.createCell(cellNum++);
                 cell.setCellValue((String)currencies.toArray()[i]);
             } 
             if(rowNum == cellNum) {
                 cell = row.createCell(cellNum);
                 cell.setCellValue("1:1");
             } else {
                 //create a key like : audcad/audeur/audusd
                 key = row.getCell(0).getStringCellValue() + (String)currencies.toArray()[j] ;
                 keyInverse = (String)currencies.toArray()[j] + row.getCell(0).getStringCellValue();
                 if(currencyRate.get(key) != null) {
                     cell = row.createCell(cellNum);
                     cell.setCellValue("D");
                 } else if(currencyRate.get(keyInverse) != null) {
                     cell = row.createCell(cellNum);
                     cell.setCellValue("Inv");
                 } else {
                     for(String currencyKey : currencyRate.keySet()) {
                         int len = row.getCell(0).getStringCellValue().length();
                         String crossKey    = currencyKey.substring(3) + (String)currencies.toArray()[j];
                         String crossKeyInv = (String)currencies.toArray()[j] + currencyKey.substring(3);

                         if(currencyRate.containsKey(crossKey) || currencyRate.containsKey(crossKeyInv)) {
                             cell = row.createCell(cellNum);
                          cell.setCellValue(currencyKey.substring(3));
                         }
                     }
                 }


             }
             cellNum++;
         }
         rowNum++;
     }

     workbook.write(file);
     file.close();
    }
}

Above code has generated the sheet like : ForexCurrencyMapping

enter image description here I have written the code for generating the sheet as of now. Once the sheet is populated through the appropriate cross links, I will start with writing the code for actual calculations.

Input to run this code would be:

console> AUD 100.00 in DKK

But this is the next stage. Right now I am just launching the main class from Eclipse to populate the sheet.

user3666197
  • 1
  • 6
  • 50
  • 92
Ramandeep
  • 41
  • 5
  • You would be better served using a web API since prices fluctuate daily. – OneCricketeer May 24 '17 at 02:24
  • Not answering your question but a general comment about storing money in doubles: https://stackoverflow.com/questions/3730019/why-not-use-double-or-float-to-represent-currency – BCartolo May 24 '17 at 17:18

2 Answers2

1

Logic may surprise: the business Terms & Conditions will Rule.

The situation is regulated not by exchange rate data, per-se, but by actual business Terms & Conditions. Theoretical possibilities must also include transaction costs, commissions and other fees, that will be accrued ( added to the theoretical exchange rate ) by any trading venue, that would provide such monetary conversion service, so the raw "theoretical" exchange rate is not a complete model of a conversion cost.


Logic & Theory to find Crosses starts from Majors:

enter image description here for which exchange rate values may change +1000~100000 times per second. If this is the reality your Project is aiming into, forget about filling in an excel table.


Daily fixing:

If your intention is different, or if such calculator is intended for being used in accounting ( under a regulated (inter-)national context ), a daily "fixing" of exchange rates may help, but - again - Terms & Conditions will apply and respective fees and commissions et al will be added to the published "theoretical" rate.

user3666197
  • 1
  • 6
  • 50
  • 92
0

You are facing with graph like datastructure. Each currency will be a node pointing to another currency based on your currency mapping. For example USD node will point to EUR, CAD, CNY etc. To find converted currency between USD to NOK you need to visit EUR node, have it convert from USD to EUR, then have EUR visit NOK and have it convert EUR to NOK and then return value back to the caller.

tsolakp
  • 5,858
  • 1
  • 22
  • 28