An APR & Rebate Calculator for the OFT
|
The DualCalc Blog ...(Page last updated: Monday 7th August 2006) I have agreed to develop a Windows rebate calculator for OFT which will carry out the calculations required by the new 2004 Regulations, so I thought I might record my progress and thoughts here in a web log or 'blog'. As is the way with these things, the entries are presented with the older ones at the bottom, so you can read the more recent ones first. Backwards text the type actually won't I strain brain undue avoid to, however. As is also the way with these things, I didn't think to do it until I had already begun the programming, so the first (ie last on the page) few entries are a bit vague as to timing etc.
PS: the log has also subsequently been used to record on-going changes after the initial development and provide an achive of the history of older versions of the program - see the menu on the right - for more recent version information see the help files packaged with the program or the CRW. Note: this log contains my personal reflections on the events described, they should not be regarded as the views of any other person or organisation. |
![]()
|
|
Monday 7th August 2006 - Log Re-opened In view of the continuing development of the program, and the growing version history, I have decided to re-open this page and transfer information on older, pre-release, versions (prior to v1.01) here. Other material may be added over time to keep the version history in the program's help files to a reasonable size.
Friday 11th February - Log Closed The Office has now obtained its own copy of BBC BASIC and the source code has been passed to them for compilation. Any further changes will be recorded in the version/history log in the program's help files, this log is now closed.
Change Log Although this blog is, technically, finished now, I will continue to use if for the time being to record any subsequent amendments to the program etc ... Monday 7th February - one more thing, while I was testing the program Friday I realised it was a bit annoying to have to keep 'manually' adding 28 days to the settlement date I wanted to use, so this morning before leaving I included a small tool to do this by adding a '+28 days' selection to the deferment selector, which adds 28 days to a date in the settlement box when you choose it. It uses the same dialogue change detection method as the settlement selector but it's really, in effect, just providing a 'button' in the selector. While showing the program to someone last week I noticed that they assumed it would understand 2-digit years in dates. Consequently I've added a function to recognise 2-digit years and convert them to the nearest (within 50 years) 4-digit date. I have also started to think about some of the 'hooks' needed to extend the program a little - eg to run other utilities which interface with DualCalc. To this end I've split parts of the load and save calculation routines out from the sections which ask for a filename. This is so the program can automatically save the current calculation before loading a utility (eg because the utility is a CHAINed BBC BASIC program which will need to re-load DualCalc and it's calculation when it's finished, or because the utility will manipulate the current calculation in some way). I realised there was a problem with CHAINing other .bbc programs because only the compiled version of DualCalc is available to CHAIN back in after. To resolve this the program now saves it's (crunched) .bbc code in the resources folder when it starts. Leading on from this I've also added a facility to autoload a calculation at startup with a -load: This new load routine also gave me an opportunity to enhance the loading of saved calculations so they can automatically run and log calculations and then chain another saved calculation - so you can batch process a whole sequence of them. Sunday 6th February - Fixed three other minor but important things:
Saturday 5th February - I was determined to have a weekend away from this but we couldn't get to the bottom of the anomaly mentioned below yesterday, and instead found another - when you added a deferment to an actuarial calculation the rebate when UP instead of DOWN ... looks like a program error but I can't find it ... so I need to resolve this. I built the actuarial routines by taking the Rule of 78 ones and adapting them - with bits of the APR routines added in for good measure. I thought this might eventually come back to bite me, but I didn't recognise it when it did, until just now. The problem with the deferment was that the Rule of 78 calculation doesn't need to add up the payments on or after settlement, so where they're needed for the actuarial calculation, I calculated them as the TAP less the payments on or before and then added the payments 'on'. But the R78's 'on or before' payments were based on the settlement date, not the deferred settlement date needed for the actuarial calculation. Consequently, while the deferment was adjusting the payments before settlement included in the formula's calculation, it was still using an un-deferred value for the payments on/after. This took ages to track down but has now been corrected by adding lines of code and variables specifically for totting up the 'on/after' values. On the plus side, I also found and corrected another rather careless error in the Rule of 78 routines - at one point the time of the last payment was checked against the deferred settlement date rather than the actual one. Still haven't looked at whether this resolves the rebate>TCC problem, but it might have. Friday, 4th February - one minor change, the actuarial analysis was now correctly calculating the 'before' values for extra payments with -ve values and adding them to the total (it had previously calculated them as +ve and subtracted). But I hadn't realised that it was also printing them as the -ve values, so now it was calculating them -ve and printing them +ve! Fixed it. Thursday, 3rd February - Only had one bit of documentation to do, describing the logged output, but noticed that there was something wrong when I logged a pro-rata calculation. Tracked this down to a simple error in the complex pro-rata routine (the simple one was okay) and corrected it. There was a similar (but different) error in the pro-rata logging analysis, also corrected. When I got to the final log in the documentation (Actuarial) I noticed a weird anomaly - the rebate was more than the TCC. Trying to understand this led me to check through the whole actuarial analysis bit again. I found a number of careless errors (wrong variables, +'s where there should be -'s etc) which I corrected, but none of these explained the anomaly. Next I tried improving the analysis routines by adding some period/days reporting and generally re-doing lots of it, this took a fair bit of time but didn't make the anomaly go away (wasn't really expecting it to). I haven't thought this through fully yet but I have an instinct that the problem might actually be the OFT interpretation of 'after' as 'on or after'. The 'right' way to do the calculation would be to include the 'on or before' payments in the formula and the 'after' ones in the sum remaining to be paid, but there was no reading of that in the Regs and we've gone for the opposite. I think the effect of this is that one of the repayments is inappropriately included in the rebate and this can tip it over the TCC early on in the loan. It all pans out when you work out the settlement figure etc, but it's perhaps an indication that there's something fundamentally wrong with the Regs (which really need to say 'on or before' in the formula's definitions). On the other hand it could just be a cock up in the program. Anyhow, finished the documentation using an example which shows the anomaly, but without drawing attention to it. Tuesday, 1st February - noticed that the HTML output had a few extraneous £ signs and was missing the odd '=' sign. Corrected. Monday, 31st January - discovered yesterday while working on the documentation that the new 'zero rate' approach led to the html writing routine falling over when a PV analysis is logged - the composite PV formula won't accept a zero rate. Simply added 'IF EAR<>0 ...' to the relevant line. Also noticed while fixing this that the Actuarial before/after analysis had no '£' signs on the amounts for regular payments or levels. Added these. Updated the build and .zip file. Saturday, 29th January - while working on documenting the entry of dates and cross-checking with the program I noticed an anomaly. Using dates and changing the PPA from Years and days to, eg, Months made absolutely no difference to the final EAR result. I managed to track this down to a missing line from the old DOS version of the period calculation routine which limited the Years and days calculation of periods to cases where PPA=1 (Years&days). I also noticed that there was no warning that the user was using periods and dates together or that there were no advances, and this lead me to start overhauling the routines to check for consistent entries and report on inconsistencies - split these out into separate routines removing a lot of duplication from the calculations. While checking this, I noticed that the dialogue was being corrupted while loading the test calculation - the dates being read in were appearing in place of 'Settlement date:'. I managed to track this down to the DD/MM/YYYY to datecode conversion routine which was still handling writing values back into the dialogue but, in this instance, was being used with no specified dialogue item - and just happened to be using the same local variable for item number as used for something else in the load routine, which was set to a value which corresponded to the item number for the 'Settlement date:' label. Corrected this. One of the inconsistencies looked for in checking the details is a loan with TCC=0, and this in turn lead me to a fairly major overhaul of the routines dealing with zero rate loans - in particular also creating a routine to calculate the sums paid, due etc for a zero rate rebate calculation. This ultimately lead me to re-write the routines for checking and reconciling the APR/PER entry for actuarial calculations again ... twice. Enough changes to warrant a version number, were I not sticking at 1.0 until pre-release. Wednesday, 26th January - decided that I should slightly alter the way the help routine works to future-proof it. Now, it checks for a local set of help files in the help folder, and only asks the user if they want to go on-line if it's not there. Tuesday, 25th January - met with one of our lawyers who has kindly agreed to check over the program before it's pre-release. Immediately hit a problem when I couldn't install the program on his PC so he could check it. It seems that on WinXP PCs where the user has some rights restrictions, or a particular 'profile' the *CD command, when used to change to certain directories, causes an error. The simple solution was to remove the *CD command which was only there to select the 'Saved' directory for Win95/98 users. [TO DO] this would be resolved by incorporating code to select the saved directory as the first to browse, this may also need an option for the user to set the data directory.
Week commencing 17th January 05: Monday - essentially I can now bring this log to an end because the program has reached a 'first draft' stage and is therefore developed. I have therefore moved this blog out of the program's help folder in to an (archival) folder of it's own. I have also skimmed through it and labelled a number of things [TO DO], so they can be found easily. These will be picked up in the fullness of time. Hey look! I got all the way to the end without mentioning again how much better RISC OS is than Windows ... Doh! ;o) I do however still have to write some useable documentation and this inevitably forms part of the development process because, while describing it in the text, you often realise that something doesn't quite make sense or could have been done better, or you check exactly how something works before describing it and hit a glitch. So these sorts of things get fixed in the process of writing the documentation. I've often wondered whether I should try actually writing the documentation first and then try to get the program to do what it says. From now on I should probably keep a, less frequent I hope, Change Log on the site so that those testing the program can check for newer versions and see what's been changed. Until testing actually starts I'll leave the program at v1.0 (beta) and then broadly follow Richard Russell's method of numbering. Version 1.0 also neatly sidesteps my programs - DualCalc v0.1 to v0.4, which are now defunct, superseded by the OFT's program. This morning I tidied up a few remaining technical issues like enabling the 'proper' error handling and recompiling the testbuild with a 'hidden' window so there is no start bar button and it sits neatly in the middle of the screen. Discovered that Richard was right about selecting folders after all - but only in XP it seems. Interestingly XP also seems to ignore the selected folder so my 'Saved' fix kind of works both ways, in XP the user starts back at the folder they last used (although they have to go find Saved the first time) and in 95/98 they always start in the Saved folder (although less convenient if they want to use another one). [TO DO] Ultimately this needs to be fixed by using the API call to open in a folder the user can specify in Options.
Week commencing 10th January 05: Sunday - want to get this finished and get on with the documentation but there's something nagging. The flag saving fix I did yesterday works but there's another flag and value used too, to store Days in year internally. When the flag's set the value is 365.25 but the program uses 365&366 days, when it's clear it uses the value. I didn't want to use another saved variable to store this flag - and anyway I couldn't think of a good name for it - so I decided on a different approach, saving 'DIY=365&366' when the flag is set and the value otherwise. Realised this was also a better approach to the deferment issue so changed this to saving eg 'Defer=Stat_1' for a statutory 1 month deferment (or _2 or _30) and leaving the 'Stat_' off where it's just a value. Had to edit all my saved examples but I'm happier with that. Also took the opportunity to fix something which had been annoying me - I had had to include 'Zero' among the combo-box deferment options for testing to stop it getting detected as 'INVALID ->'. Managed to get rid of this and the user can now enter '0' or Zero and have it accepted. I think that's pretty much it for the programming - of course I will be proved wrong. Decided to take a look at the image map idea for the 'interactive' help. I have some RISC OS software to do that, to I grabbed a copy of the dialogue using the -display switch (did I mention I added a facility so none of the boxes are greyed if you put '-display' in the command line?) and saved it as a .png., Converted it to a Sprite in RISC OS and after a bit of a false start, mapped out all the areas - fifty-bloody seven of them, my eyes, my eyes! Save the client-side code in HTML and tested it in Oregano2 (A RISC OS browser) all seems okay. The various rectangles in the map are labelled area1 to area57 and these will appear if you hover over them in IE and some other browsers - I'm sort of hoping a load of ufologists are going to end up here after googling 'Area 51' - but I doubt it. Finished up by shuffling around the files and folders a bit to prepare for adding proper help files. Got a bit side-tracked. My ISP's server is easier to use if the names are all in lower case and they weren't. After renaming about twenty by hand I gave up and wrote a little RISC OS program to go through all the folders and sub folders renaming everything to lower case. Put it all up on the site. Saturday - yes, I know, Saturday morning. Did a little more testing and discovered some glitches in the HTML building routine - I think I got all these ironed out but it's time to go see Man Utd thrash Liverpool. ... time passes ... Okay only 1-0, and 10 men in the end, but it's three more points. While doing further testing on the HTML generator I noticed that the load routine wasn't picking up the deferment correctly. Realised I hadn't done anything to save whether the deferment value was statutory or not (internally the program uses a flag and a value to store the deferment, if the flag's set only values of 1, 2 or 30 are used and they mean the statutory deferments of 1 month, 2 months or 30 days, if the flag's clear, the value is counted in periods - the way I had it 30 days would have been loaded as 30 months!). Fixed this by saving the flag as well with the name 'StatDef=' and modifying the load routine too - all seems okay. Friday - working at home. Put simply, added an actuarial rule analysis. In a little more detail this also involved: - adding to the calculation save routine so it remembered the setting for outputting analysis details
- re-doing the conversion of APRs to period rates in the actuarial calculation to ensure that the truncated or rounded rate is used. - a general run through of some of the code and miscellaneous minor additions/amendments I am concerned that the time I was expecting to spend adding the printing routines was instead spent adding the analysis code to the logging routine. I feel I'm running out of time and still need to make a start on the documentation so, as there is a 'quick fix' available I've decided I will use the user's browser for printing as an interim measure. I've split out the code to output the results of a calculation in HTML into a separate routine and added a printing routine which is very similar to the logging routine apart from always starting a new web page and using a version of the standard template which includes 'onLoad=print()' in the pages body tag. It also automatically opens the page once it's built. So, when the user clicks 'Print', a new web page containing the result is built and then opened and the print() command starts it printing. That sounds good, but what happens next is the print dialogue is thrown up and the user has to click on the Print button in that ... and then close the browser window afterwards, so it's a bit irksome really. However, this is only a temporary measure [TO DO] proper printing routines are still on the agenda. Sadly on testing I discovered that, on Windows 98 at least, the compiled program does not seem to operate as Richard Russell suggested, remembering where it did save/loads last time. It always starts in My Documents. However, I noticed that simply choosing another folder in the program code beforehand overrides this, so it is possible to make the program start in the 'Saved' folder. Ultimately the user should be able to select their preferred folder, in an extended 'options' dialogue. Thursday - updated this log at home before leaving. Felt a bit yuck when I got to work but started on the analysis of R78 calculations. Finished these but felt worse and thought I'd better go home again. However, I obviously wasn't concentrating and as I was about to leave, discovered I'd mucked up a big chunk of the logging routine. Didn't want to leave it in case I lost track of how to fix it, so I had to do that first. Felt a bit better when I got home and managed to finish the R78 analysis and add Pro-rata analysis (very simple) in the evening. Wednesday - checked my mail this morning and had a reply from Richard Russell. Extremely helpful (as usual) both in explaining how to open a particular folder in more detail and in how to determine the page (printable area) width. Armed with this I could start on the printing routines but, on the way into work, it occurred to me that the logging routines hadn't implemented the 'analysis' option - this provides the user with more information about the calculation in an effort to deal with the possibility that, eg, a court might ask a TSO to 'prove' that the APR result is correct. It does this by adding to the output details of PVs and their totals for APR calculations, the top and bottom halves of R78 fractions etc. I mused for a bit about not bothering with the analysis routines (these were a refinement of the more advanced versions of the DOS programs) but then realised that they were very important in the testing stage because they provided a way to double-check how the program had done the calculation - they really do need to be there (they're probably also going to be useful to the Office internally for producing guidance material, because they'll spit out all the figures for examples). First thing when I got in was I discovered that the options dialogue wasn't retaining the current setting for the 'Analysis' tick box, so I fixed that and also thought to add 'Details=' to the switches which could be set by Setup.txt. Then I ummed and arred a bit about whether to do the print routines first and then add analysis details to printing and logging, or spend more time on logging to implement the analysis stuff there. Reasoned that if I had the analysis stuff in logging it would provide a model for printing too so I should probably concentrate on that. Slow going - but, by the end of the day, I had built the logical structure for analysis and added PV details to complex APR output. The logging routine is getting very long, maybe I should break it up a bit. While testing what I was doing I discovered that it is a pain to keep the logs and saved calculations in different folders. Since they are different file types (htm and txt) only the relevant ones appear for the relevant load/save actions and, so I moved them all into one 'Saved' folder. NB: Forgot to mail the source code home so it's still yesterday's version here and the load/save/log routines may be broken because I typed complete nonsense instead of the correct code to check whether the user had added an extension to a file name. Tuesday - quickly implemented a couple of configuration facilities before leaving for work this morning: the file 'Setup.txt' in Resources can set the switches to determine the type of calculation displayed on startup and the file 'Maxima.txt' can be used to determine the maximum numbers of advances, levels and extras the program will deal with. Both are in 'saved calculation' format and Maxima.txt uses the 'Advances=', 'Levels=' and 'Extras=' indicators for the maxima. Due to a rare piece of forethought the VCR handling and dialogue building routine (which uses different buttons and actions based on the maxima) had already been coded to cope with different values - as had the code to ensure that the maxima were rounded to the nearest ten so as not to confuse things given that there are ten entries in the panels. There is a trigger value for the different actions - maybe that should be configurable too? I was concerned about how I could make the program open a particular folder when you browse and emailed Richard Russell. He tells me that Windows automatically opens the last window visited, so that shouldn't be a problem with the final compiled program - I was not getting this effect because I was running the .bbc code from the editor. He has mentioned how to access a particular folder but I didn't really get it and it's not that important. At work I had some proper job stuff to do and then turned to the printing routines. I started by adding the code to call the Windows page setup dialogue from Richard 'Hints and Tips' page on his site and a button in the Options dialogue to pull it up. Then I started to look at printing, the only problem I can see is that, with proportional fonts, you have to adjust the place they're positioned on the paper to do things like centring. Richard provides code to measure the length of a proportional string and shows how to, eg centre it on a given positions across the paper. But I can't see how you work out the width of the printable area so you can centre stuff on the page or, say, right justify it. So, I've prevailed upon him again to see if he can tell me how to do this. In the meantime I think the best thing to do is copy over and adapt the logging routine, but not worry about justification yet. Monday - due to an hilarious (actually just plain stupid) 'wrong trousers' incident, I arrived at the station this morning with no season ticket, credit card or money (even more amusingly, I had just enough change to get there on the bus - but only half-way back), so I'm back here at about 9:45am working at home again. Please bear in mind that a bloke who can't even dress himself properly is writing this program :-O~ (drooling). Spent all day ploughing on through the logging routine until I got it finished - slightly gob-smacked at how much thought and code was involved in the end and I also had to alter a few other things (like separate the 'number formatting' code from the 'writing it into the dialogue' routine) to integrate logging better. Ran it with some basic examples until it would go through to the end without error and amended a few glitches in the format. It's not been otherwise tested but I've put a build up with this blog entry. NOTE TO SELF: there are a few things mentioned here (like HP half and third info) I haven't done anything about yet - I need to read back through this. Had a vague thought about NOT writing a printing routine, ie using IE (can you say that?) and the Javascript print() function instead - probably daft and annoying to users, but worth thinking about as I now have all the code for the layout in HTML. Anyway the logging code should at least provide a framework for printing ... also noticed something about page setup on the BBC BASIC website - I need to look at that too. Oh ... oh ... and the files open/save routines need to add extensions when the user doesn't. It's about half six now so I've had enough for today - and anyway I need to spend some time on trouser recognition exercises.
Week commencing 3rd January 05: Friday - working from home today, started about 7:30am and by 9 I'd finally got the APR/PER reader right. Realised that the simple versions of the file open/save dialogues I was using (in BBC BASIC for Windows, if you open a file with a wildcard name, it automatically calls up the dialogue) weren't really good enough, so I substituted routines which call the Windows API. While testing this I noticed there was something wrong with the complex R78 routine - it was giving the total paid as zero for level only loans. Found I'd moved, instead of copied, some of the code to the complex Actuarial routine, so I put that back and it's okay now. I'm still not sure about the complex Actuarial routine though - regard it's results as suspicious! After lunch I added some code to the program initialisation so that a '-display' switch in the command line will cause the program to initially switch everything in the dialogue on. This is purely to generate a dialogue that can be used for the help files. The result looks like this:
Wrote a routine to select and display a log file (really, any HTML file) so I could examine the results of the logging routine when I wrote it. Began work on the logging routine. It will use a template file which the web-skilled user can amend but started by getting the program to write a simple default one if none is present. Wrote the basic file handling structure for the routine and dumped the code from the save routine in there in 'pre' tags, just so there would be some output. The way I've decided to work it is as follows:
Began to test this but there are some strong winds today and they seem to be getting the better of our power supply. The lights keep flickering so I'll give it best now before I lose something, it's 4:30 anyway. Thursday - completed the load routine, tested it and corrected a few glitches. Save/load all seems okay now, apart from the APR/PER in actuarial calculations. Decided I wasn't happy with the section of code which read the APR and PER from the dialogue and basically re-wrote the whole thing, but it's still not quite right. Added some code to the initialisation so that the program makes its resources folder if there's not already one there. Wednesday - had some 'regular job' stuff to do in the morning and a meeting in the afternoon and then continued with the load routine. Not much progress today. Tuesday - began with a mail to the credit teams about the questions mentioned below. Continued work on the loading routine. I have chosen a slightly slow approach where the routine scans the entire file for the first occurrence of each of the variables which make up a calculation. This way users or programs which construct calculation files won't have to be particularly careful about the order in which stuff is put in the file. I added my standard recursive file search routine to the GENLIB code and wrote a small function FNscanFor("text") which uses it to look for "text", starting at the beginning of the file, and then return the text from "text" up to the next terminator. A 'terminator' is comma, semi-colon, space, tab (ASCII 9) or CRLF (ASCII 10 or 13), to allow programs to generate calculations in a number of formats. So, if the file contains 'Loan=1000' followed by a terminator (by default a CRLF - this is how DualCalc saves it) then FNscanFor("Loan=") (incidentally, it's case insensitive) will return "1000". Finished splitting out the date checking routine and this seems okay. Monday - decided to take a look through the code to 'tune back in' after a week away before I start back tomorrow ... and ended up writing some. I completed a calculation saving routine and began the corresponding loading routine. I will need some way of checking whether time values in saved calculations are dates - I'm in the process of moving the checking routine in FNreadDate (the function which reads dates from the dialogue) to a separate validation routine. The format I've chosen is a simple series of text lines (ending CRLF) which have the format variable=value (eg, Loan=100, Initial=0, etc). I abandoned the XML format idea, easy to save but harder to parse in the way I wanted to when loading. It should be possible for users to construct saved calculations themselves (eg with other software/programs - not much point in doing it manually!) to generate calculations the program can load. I will eventually add 'variables' which will tell the program to do the calculation, log or print the results, and load another saved calculation - this way it will be possible to batch process a number of previously generated calculations. As part of the saving process, I had to move the reading/checking of the APR/period rate entry for Actuarial calculations into FNcheckData and have REMed out the part of the Actuarial calculation which calculates the APR first. I have also decided not to implement simple Actuarial calculations at this stage, because they provide no date entry facilities and, the way the Regs have been written, virtually all calculations will require date calculations (because of the 28-day deferment and Reg 11 TCCRs). Need to talk to the credit teams about this decision, and about whether the current method of calculation will need to be retained (eg so users can do 'pre any later change to the Regs' calculations. I also altered the way that the program displays it's copyright message, it now does this every time it processes a user action, that way the individual actions which change the info line at the bottom of the dialogue don't have to bother, and they have been altered correspondingly. NB: the build has not been updated yet, because I've not checked these changes are all stable.
Week commencing 27th December: Monday - Friday - on leave.
Week commencing 20th December: Friday - on leave. Thursday - on leave. Wednesday - tidied up the settlement code in the morning and worked out and REMed in how to add lastPay into the rebate calculation if needed. On the train in I decided I'd try to find out exactly what the formula in the Regs was doing and, although I only had a simple 'Planner' type program in my Psion, it seems pretty clear that what it's doing is calculating the balance due - including the instalment due on the settlement date. I thought that was a bit odd at first but I'm guessing that GAD gave DTI a formula to calculate the sum due on settlement (ie everything due, including the repayment) and DTI then had to convert that into a rebate calculation because s95 of the Act only allows for a rebate formula. The meeting with the lawyer and a the credit colleague was very useful and I now understand that there is an argument that the wording in the head to Reg 4(1) can be read sensibly to include the payment due on the settlement date because of the conditional clause about 'if settlement did not take place' - ie the initial premise is that the borrower is going to settle, so the instalment due on that date is catered for by being left out of the rebate formula and hence remains outstanding. However, if they changed their mind and didn't settle on that date, then the instalment would immediately thereafter become payable and so should be included in the sums from which the result of the formula is deducted - and this is re-enforced by regulation 3(1) which requires that 'the rebate shall be calculated by reference to all sums paid or payable ...' (my underline) so you can't just leave one of the payments out entirely. Okay, I feel that's a bit of a stretch, and we agreed Reg 4(1) really should say 'on or after', but I can accept that if it's the Office's view. Of course what this does not explain is why the example completely contradicts this by saying that the balance 'after' payment of the 12th instalment is calculated 'according to the formula' and including the 12th payment in the formula so that it does. I understand from the credit team there are some other problems with this example too, but the Regulation takes precedence (Reg 4(3)). Changed the program to incorporate the lastPay adjustment. I also realised that the user might want to enter a period rate rather than APR so both these now open with the APR being used for preference and the period rate only if the APR's not entered/valid. I'm on leave until January 4th so that's probably it for now. Tuesday - there seem to be quite a lot of issues in the examples and I spent a good bit of the day wearing a groove in the floor between my desk and the credit section:
There were some emails between myself, the credit team and our lawyer specialising on this subject, on the 'before' and 'after' point and we've agreed to meet to discuss it tomorrow morning. In the meantime, I looked through the code of the settlement calculations for a fix to include the 'on' payment in the calculation and came up with a pretty simple one - the program also calculates the sum payable on the settlement date so it can report the total payable, settlement figure plus final payment and, if this figure should be included, all I need to do is add it into the rebate calculation. This also gave me a chance to look through the settlement calculations again and pick out some things which need tidying. Monday - spoke with the credit team about some of the further points I'd concerns about. As the main problem was the way I'd interpreted 'before' and 'after' and the conflict with the first part of the first example in the regulations, he felt it was better to check my interpretation with our lawyers before approaching DTI. He also mentioned that DTI now accept that the agreement's original APR must be used for the actuarial calculation and will amend their Guidance - so there is no alternate 'DTI Guide' calculation. As an interim measure I have blocked out the method (now called 'Revision') which calculates the APR first ... although that maybe should be available in the test phase. Decided to get on with my proper job because I couldn't really do any more until this was resolved.
Week commencing 13th December: NOTE: the current test build seems to give the wrong answer for actuarial rebates - ie it doesn't agree with the Regs. Friday - spent most of the time looking through the Regs and scribbling diagrams until I eventually wrote some calculation code for the complex actuarial routine but they don't work correctly yet as far as I can tell. I have however realised that I can use the FNlevelPV() and FNextraPV() functions to do the calculations, the level one needed a bit of thought as the times are all counted up to the settlement date rather than on from the relevant date, but in the end I just used them 'backwards'. Bit of a frustrating day generally, every time I look at something in the new Regulations it just raises more questions:
My brain, my brain! To cheer myself up I implemented the mechanisms to do both complex Actuarial and 'DTI Guide' calculations in the one routine. PROCgreyMode() has been modified for the umpteenth time so that it opens the APR box when the user chooses an actuarial calculation, and the calculation routine also pulls the value out of there for actuarial calculation or calculates the APR and puts the rate in there first for a DTI guide calculation. I've just noticed while writing this that the first example in the Regs has no deferment, so things might not be as bad as I thought. Oh, and I made the icon a bit more colourful. Thursday - on a half day but began working in earnest on the Complex Actuarial calculation. Wanted to ask the credit review team whether the calculator should allow thirty-day deferment when the user was not using dates but they were out, so I made a unilateral decision that it would reject such calculations and ask for date entry. Built the basic structure of the routine from the complex R78 version but it doesn't do anything useful yet so I'm going to put a test build up. Visiting the R78 routines again prompted me to do a bit of simplification. I've written a function FNlevel78() - all of about 30 bytes - to sum an R78 level and used this in both the complex and simple calculations. Also noticed I'd forgotten to deal with the Final payment in the complex calculation (oops) so corrected that. Also re-wrote the calculation in the simple R78 routine so that they used the settlement and deferred settlement dates - rather than the settlement date and the length of the deferment - this makes the simple and complex versions consistent. The credit team told me that DTI confirmed my assumptions about the calculation of r - so that's okay. Wednesday - finished off my general tidy up in the morning and had a Christmas drink in our section lunch time. Went back to the Actuarial calculation in the afternoon and didn't understand DTI's description of converting APR to r in the formula, so I looked at the Regs and didn't understand that either - thought it was the drink at first so went back to my colleague dealing with the Regs and he saw the point that the Regs are ambiguous. They say something like r is 'the period rate equivalent of APR/100', but does that mean '(the period rate equivalent of APR)/100' - I think that's what it should be, ie the period rate expressed as a decimal' or 'the period rate equivalent of (APR/100)' which seems just nonsense. I don't think there's a problem in terms of the program here, but what if a lender starts giving, or consumers start demanding, rebates based on the second method? Need confirmation from DTI that the first version is their view though. In the meantime, I decided to enhance the series entry so it would do advances too. This kept putting stuff in the wrong arrays (extras instead of advances) etc. until I finally discovered that several of the combo box routines (called to check the data before the series is added) were using the same variable which determines extras/advances without it being declared as LOCAL - so they were changing it and then the series routine was putting stuff in the wrong place. At COP the credit team came back to me for a brief example of how the two interpretations caused different results which he's going to mail off to DTI. Tuesday - had a brief informal meeting with a couple of the credit team to show them progress so far, ask for any comments and check on a couple of questions: whether advances should be disabled when R78/PR rebates are used and whether the program should display HP half/third info in price calculations. The answers were seems okay, 'yes' and 'yes', although it was rightly pointed out to me that you probably wouldn't fire up this calculator just to calculate the HP figures. Began to look at the Actuarial calculation and hit a problem with DTI's guidance. They seem to be saying that payments falling within the deferment period are payable by the borrower and I think that's wrong. As in the old Regs, the new ones say that the deferment is 'for the purpose of calculating the rebate' or something similar, not for calculating the sum due - ie the deferment reduces the rebate a bit but doesn't mean the borrower has to actually pay payments due after they settle. Checked with a colleague in the credit review team and he's going to talk to DTI. As this would affect the way the DTI Guide calculation was coded (and might mean separate routines for that and the Actuarial method) I'll have to wait for an answer. Fiddled around with some general tidying up. The combo box routines were all using different variables for the same tasks so I made them uniform and shortened the way they handle 'INVALID->' reporting. While working on series entry I noticed that the date reading routines didn't write dates back into the text boxes so I added this and also removed the evaluation of non-date entries as this seemed a bit ill-thought-out: how should the program distinguish between a date and a calculation which has two decimal points or two subtractions or divisions in it? This might need a bit of a re-think. Also discovered a few more things where I needed to 'generalise' the dialogue handling. At some point the credit team came back to me with the information that DTI didn't mean to say what they'd said, so I should treat it as a deferment in the normal sense, but it's near COP ('close of play' - civil service speak for the end of the day) now so I'll turn to that tomorrow. Monday - Looked up the formulae for the simple R78 calculation, copied and cannibalised the complex code before adding the simpler formula. Worked first shot, so that's crossed off. Decided I needed a bit of restructuring of the four routine plan below and made it a little more hierarchical. Now the calculation routines are structured in three groups - APR, Rule of 78/Pro-rata and Actuarial/DTI Guide, each of which has simple and complex versions. There is an initial PROCcalculate which branches to PROCcalcAPR or PROCcalcRebate. PROCcalcAPR does the data checking and, in the case of complex calculations calls PROCtidy and PROCtotalPays before going on to PROCsimpleAPR or PROCcomplexAPR. PROCcalcRebate is an additional layer in the hierarchy which branches to PROCcalcRule78 or PROCcalcActuar and these then act like PROCcalcAPR by checking data etc before branching to simple or complex versions. Hooked all that together and it's working well. Thought some more about controlling the setup for printing. I didn't think the simple switch from Standard to Detailed output was really enough, the user needs to be able to pick a printer and probably a font too. Changed the button to a 'Format' button which opens another dialogue containing print and font setup buttons (which in turn pull up the standard Windows dialogues) and a tick box for including the extra details, this all pretty much worked first shot, but doesn't do anything yet because there are no printing routines:
(Just realised that I've used the RISC OS vernacular 'Dismiss' - this should probably be 'Close' ... and why is the prompt for the tick so long? 'Include analysis:' would do.) Having produced one additional dialogue, I got slightly sidetracked into series entry. Wrote an additional dialogue builder for a small dialogue with which the user can enter the amount, start time, interval and number of payments, a combo to select intervals as periods or months, and an 'Add extras' button to start inserting the payments in extras. This still needs to have some code written for the combo and the actual insertion code.
Started work on the series entry stuff but kept coming up against the problem that all my library routines for dialogue handling were designed to work only on the main one. Now I had three dialogues I was having to treat the series one (the format one was much easier) as a special case and write specific API calls for it every time. The fix was simple, all I had to do was include the dialogue handle as one of the parameters passed to the library routines, but it meant that, as soon as I'd altered them, the entire program was broken until I'd found and modified all the calls used for the main dialogue. This took quite a time. When I'd got that fixed and was testing it, I noticed that the simple and complex rebate calculations were giving different results for the same loan when Extras were used. Thought I was in for a lot of back tracking, but I decided to start by throwing back the values for the amount and time used in the extras routine and immediately discovered that they were zero. It turned out I'd typed N% instead of n% when reading the amount from the array. As N% is one of BBC BASIC's 'static integer variables' which always exist, I wasn't getting a 'No such variable' error but as I don't use N% it was zero, so it was reading element zero of the array, which also isn't used and contains zero, hence all the extras were treated as £zero - grrr. I'd written a few lines in the complex rebate calculation to add x months to a date (for adding deferment) and realised this would be better as a general routine so I could use it to add months to a series as well. Transferred it over but completely cocked it up and didn't notice until later. Discovered that the use of multiple dialogues needed a bit more thought - eg what to do if the user clicks on the close icon for the main dialogue while one of the others are open. This needed a bit of a re-write to the basic wimp poll routine (sorry, RISC OS terminology - the bit where it sits and waits for the user to click something), at some point this caused another BSOD ('waiting for the close program dialogue to appear') but Windows acted a little more intelligently this time (ie it actually knew it has crashed on a restart) and it's been stable since. The dialogues all seem okay now. Went back to the series stuff and realised that it needed it's own wimp poll and it's own checkData() equivalent. Implemented these and started on the filling in the extras bit. Came to a bit of a stop because I couldn't make up my mind what to do with certain input circumstances: if the user enters a start and relevant date and chooses intervals in months, fine, all the extra entries are dates x months apart; if they enter a start time and choose intervals in periods, fine, the extra entries are times calculated as start+n*interval; if the user enters a start time and intervals in months, uh, uh, they have to give a start and relevant date for month entries; but what if they enter a start date and intervals in periods. Well they still have to have given a relevant date or the start date is useless, so that's a no, no too. What I settled for in the end is, if they've given a start and relevant date but choose intervals in periods it calculates the start date as an integer (rounded) time and then all the time entries are calculated as start+n*interval. I think that's what the user would expect. Series entry is crossed off the list.
Week commencing 6th December: Friday - The credit team arranged a meeting for this afternoon with me, representatives of the credit team and IT at which it was agreed that I would continue development as before. Sadly this has cost us a week. I added the dialogue stuff to the complex Rule of 78 routine and modified greyMode() - again - so it would deal with enabling just the TAD, TAP and TCC results for rebates, and also grey the Advances entries for complex R78 calculations (not sure this is strictly necessary but, since the statutory R78 calculation doesn't allow for multiple advances it seemed appropriate). Bodged the R78 results section slightly so they will clear the rate results - this should probably be in greyMode() but it makes more sense here. [TO DO] Thought about using the spare rate entry boxes to display the 1/2 and 1/3rd HP figures for price calculations as this info was provided by the DOS programs - I'll ask the credit people if it's useful. Greying the advances was quite interesting, to do this I had to detect changes to the combo box in real time, not just when the user clicked a button. I thought you couldn't do that and have compromised on this in other programs, but I though I'd have a go a doing the detection inside the system call loop of the poll routine and it worked! Ah well at least I've learned something useful. There is a bit of 'flickerage' if the user types something in the combo (it repeatedly labels it 'INVALID->' until they select from the combo again, this probably won't be visible on a faster PC and I can live with it. Haven't done much testing of the Complex R78 calculation yet but it all looks pretty much okay. It uses the same trick as the old programs, do the R78 calculations and then replace the resulting fraction value with a simpler Pro-rata fraction, so it handles these calculations too. Crossed them off the list below. NB: currently, the test build is still the one from last week. Thursday - no change. Wednesday - no change. Tuesday - no change. Monday - no change.
Week commencing 29th November: Friday - no change. Thursday - Had no problems sorting out the remaining dialogue positioning issues at work, this may be because I was using XP or because one of the first things I did was increase the dialogue workspace in FNmainBuild(). Began again to work on the rebate calculation by incorporating the old code (although it will subsequently be substantially re-written), not sure whether to have one routine which deals with all the rebate calculation methods or split them up - the former would probably be more efficient, but more complex. While considering this, I decided it would be better to incorporate the two APR methods (Newton's and Bisection) into single routines, so I did this, considerably tidying and shortening the code. I thought about further compressing the simple and complex calculations into a single routine but decided not to, because it's always possible that they will be useful in other programs. Added messages to the buttons which don't work yet, so that everything in the dialogue is hooked up now, I just have to write the actual routines. Decided to remove the 'Dual' option from the APR/Rebate button as it might encourage users to do the wrong sort of calculations and, while I was at it, changed the name to just DualCalc - as it will be '05 before it's finished. Decided that I probably need four rebate routines:
PROCcomplexRule78 (as above) PROCsimpleActuar (which handles Actuarial and DTI Guide methods) PROCcomplexActuar (as above) Very roughly implemented the Complex R78/pro-rate routine, still need to be tested and have the results written to the dialogue - Currently greyMode() is opening the APR result too - this need to be corrected for R78/Pro-rata. However I've hit a non-technical problem ... my colleague in the credit section who approached our IT people to obtain the Office's copy of BBC BASIC forwarded me their initial response which raised concerns about the cost of licensing BBC BASIC and other matters, and questioned whether someone else in the Office, rather than me, might be better placed to produce a solution. In view of this, particularly the last point, I am concerned about the time potentially wasted working on this so far and have suspended development of the program until decided whether I should continue. Clearly I am not pleased about this and am worried that, if there is a lengthy delay while this is sorted out, the project will be set back by having to later pick up the threads from where I left off. Wednesday - Working at home because my head feels a bit like I walked into a cupboard door or something. Great start, when I looked at the version I'd sent home it was before I'd finished sorting out greyMode() or done the Deposit stuff - so had to start by doing that again. Began dickering around with the interface again. Moving the rebate result down has given me room for an extra button and I think I'm going to use it to move the Round/Truncate button out of the APR results. Meanwhile I added what I've labelled the Standard/Detailed button to toggle the logging/printing of additional information. Also decided that, as in the old programs, further advances should not be available with a Cash price and deposit calculation, so these are now greyed when the user chooses 'Price' in complex mode. Tested the Cash/price and deposit calculations and didn't believe the answers. But when I tried it on the old programs, I got the same answer ... actually, yes, this is right. Also implemented the rotation of the APR/Rebate button to allow for APR/Rebate/Dual (thought I'd better use 'dual' as that's what I've called the program) and modified the calculation routine to run one, the other, or both (APR first). Began work on the implementation of complex rebates (Rule of 78 first) by modifying the totalling routine to calculate the time of the last payment in the loan (needed to determine if the user enters a settlement date/deferment which is after the end of the loan). This meant I could also implement the use of 'Final sum' in complex calculations so I did that for APR and modified the dialogue so that it is no longer greyed out for these. At some point it suddenly dawned on me that a solution to the slightly odd position of the extras panel would be to put the payments (levels and extras) on the left and the advances in the lower position on the right (I think it was seeing them greyed out for Price calculations which triggered this). This prompted another re-vamp of the dialogue - particularly because I realised that the basic payment and timing information needed to be swapped at the top too so that the payment info was still above the regular/number info in simple calculations - and these moves generally required a pretty major overhaul of several parts of the code. I also moved the Round/truncate function to a 'proper' button on the left but at some point while trying to tidy the results display having done this I hit an annoying snag because the program kept crashing Windows in a rather worrying 'Blue Screen Of Death' way and, when I re-booted Windows sometimes didn't even seem to know it had crashed (no checkdisc on startup etc). Here's a fairly recent version of the display, the .exe file has not been updated because I need to iron out the BSOD problem first:
Note the dodgy 'period rate' position! Head's still a bit dodgy but I need to get to the Office tomorrow to try and sort out the crashing - I could try putting back the results code from the earlier version there, and maybe increasing the size of the dialogue buffer a bit? Hopefully WinXP at work will be a bit more stable than my old Win98 ... Windows ... stable ... hah! Note to self - the previous code is on the server as 'DualCalc04A.bbc'. Tuesday - Bit of an annoying day really. Refined the buttons a little and updated this log at home in the morning before going in and continuing by modifying the dialogue load/save stuff to incorporate the revised layout. Had a migraine in the early afternoon so I couldn't really see the screen for half an hour or so and, when I started work again, my PC wouldn't recognise my password. Our IT people re-set it for me and, when I restarted, the version of the program on my desktop was the one I'd sent from home that morning - all the subsequent 2-3 hours' work had disappeared. Great. It seems our hard drive isn't really our hard drive it's on the network, or overwritten by a 'profile' held on the network - this seems to be so we can walk up to any PC on the network, log on and see 'our' PC setup, nice idea, but really annoying when it goes wrong and has to use an archived setup from a while back. Re-did all the morning's work and then added Loan/Price (as I've called it now) switching. Spent the remainder of the afternoon holding my head, whimpering in a pathetic fashion and sorting out greyMode() to put the switches in the right order (told you I would). Also looked at how the program should actually deal with Cash price/Deposit - it seems ridiculously simply, all I seem to have done in the old programs is subtract the deposit from the total advanced after it had been calculated in the usual way for loan/initial agreements, but thinking about it, that may well be right. Monday - Very little progress today, re-thought some of the buttons and incorporated some dialogue changes to cope with some of Friday's thoughts. See the .exe file for the changes in detail but briefly, The calculator and calendar buttons have been removed, they can be accessible through the 'Others' button if and when. I intend to replace these with two further toggle buttons, one towards the top which switches between 'Loan and Initial sum' (the new shorter name for 'Initial payment') and 'Cash Price' and 'Deposit' - it'll probably just be labelled 'Loan' and 'Cash Price'. The second will be above the Log and Print buttons (and, like them, only accessible when results are displayed and will toggle between something like 'Standard' and 'Detailed' to trigger the logging/printing of PV analysis for an APR calculation and Rule78 fractions or whatever for a rebate calculation. To cope with entering excluded charges I used the 'blank line' at the bottom of the Rebate results, putting APR and Rebate results in separate group boxes with the Rebate ones moved down a line. Then the Extras panel was moved down a line into the vacant space and an 'Excluded sum' text box put in the gap, under the other Rebate entries. Not too sure about the Extras panel being out of line with the others, but it makes everything else fit neatly. I modified PROCgreyMode() to work with the button revisions and the Excluded sum entry (so it's only available for 'Rebate' calculations) but I also need to:
Aside: had a vague thought that the APR/rebate button should cycle through APR, Rebate, Dual ... Wrote to the credit team to remind them about getting a copy of BBC BASIC and some test volunteers. They're writing to our IT and Web people about the purchase and distribution issues. Gave them the mail addresses of a dozen or so TSOs who'd contacted me over the past year as possible testers.
Week commencing 22nd November: Friday - continued with the date stuff but progress is slow. Eventually realised that I was struggling with a fundamental misapprehension by linking the days in a year with the periods pa. Here, in a slightly jumbled fashion, are my thoughts:
The program ultimately needs a time value for the calculations and will need to convert a date to a time in years and days and also, if requested, into weeks, months or some other period. The program already includes a routine from the old DOS programs which calculates the period between two day-numbers in years and fractions of a year where the fraction is calculated according to the DIY value - and taking account of leap years and 365/6 days if that is being used. I have adapted this to use the FIVESIX% flag (which indicate the use of 365/6 days) in the current program. For quick+dirty use of other periods all I need to do is multiply the resulting value by PPA, partly justified by the regulations telling us that there are 12 or 52 periods in a year. Sorting this out has made a lot of the problems I was having go away - and made the program a lot simpler (and, I hope, easier) to use and code. I was, in fact, able to add the complex APR calculation in about half an hour ... and under my new date -> time conversion regime this includes the 365/6 calculation. In fact I should now be able to cross these off two at a time because the time conversion now automatically copes with 365/6 (incidentally - all the stuff from Tuesday about 365/6 daily calculations can be consigned to the mental rubbish bin now). Did some basic testing of the Complex calculation. The way I do this with most programs is to set one calculation and approach off against another and check the result - the example I generally start with is the very basic £100 loan repaid by 12 equal monthly instalments of £10: TAP £120, TCC £20, APR 41.3 (EAR=41.299898415). To test that the levels stuff is okay I split the 12 instalments into two or three levels, eg 5, 2 and 5 payments long. This should give the same results. Then I replace a couple of the level payments with extras ... so the middle two payments are now of amount Zero and there are two Extras of £10 at times 6 and 7 ... again I should get the same answers. Checking the advances is a bit trickier but one simple thing to do is stick two loans together ... ie advances of £100 at times 0 and 12 and a level of 24 payments of £10, you can also offset advances and payments ... stick in an advance of £1000 at time 99 and a payment of £1000 at the same time, and they should cancel out giving the same answer ... and so on. Quickly tracked down and corrected a couple of minor errors with this and now feel I can cross the complex APR stuff of the list. My next target should be the complex Rule of 78 rebate calculation - my thinking is that knocking this over will also automatically kill off the Pro-rata calculation (the procedure's exactly the same, then you throw the Rule of 78 fraction away and do a simple division instead), and should provide an easy route to the simple Rule78/pro-rata calculations. The structure of the new calculation, although using a PV analysis, will also be very similar ... oh look, what's that?
Dragged what seemed to be the relevant code out of the DOS programs, and made some notes about the variables (included below for my reference): meth%=1 ... pro-rata rule max : end time of loan last : settlement time lastA : sum of payments made on settlement time paid : total payments up to and including settlement time set : deferred settlement time excl : excluded charges (damn!) That's it for this week.
Thursday - for the record, this is the thirtieth anniversary of my joining the OFT! Working at home today and tomorrow. Okay, addressed the two outstanding problems from yesterday:
Nope, can't switch the X off by any obvious route I could think of, so I experimented with adding a close button and a reset button instead - I added the code for three narrow, tall buttons on the right of the results panel, but have REM'd it out for the time being. Back at the calculation, for one glorious moment though that I was going to be able to produce a working routine in about ten minutes ... but that soon evaporated. I'm still having problems getting my head around how dates and/or 365/6 day calculations are going to be handled. Played around quite a lot with the basic PV and derivative routines but couldn't make my mind up as to whether they should deal with date to time conversion or it should be done in the various calculation routines. I still think there's something basically wrong in how I'm dealing with dates. Looking at the code of the old DOS programs, I stored all times as times and a flag indicating that the user had entered that time as a date. This could create some minor discrepancies when the user printed or re-entered dates, because they had to be converted back to dates from the stored times based on the Periods pa and Days in a year settings. I have tried to avoid that here by storing the actual daycodes when the user enters a date - that way they'll always get the same date back - but this means that the date has to be converted to a time during the course of the calculations ... hmmmm, actually that shouldn't be so difficult if you know the date and the other factors, but there are two 'factors' and only one user input for them? Started to scribble a 'truth table' of the possible combinations and came up with something like this (rdate=relevant date):
There's still something missing here. Some other random questions have also occurred to me:
Wednesday - took a look at the compaction stuff this morning after sleeping on it. Managed to sort it pretty quickly so the routine works for all elements and returns the correct last valid element, including where there are none and where it's the last one. This broke the panel display routines because they need an index of the top element in the panel minus one - and zero where the last element is full so the panel wraps around to the start again. Wrote a small function called topTen() which produces the right index from the value now returned by FNcompact(). Right, back to that pesky complex APR calculation routine ... ... Or maybe not, because I got sidetracked into improving the 'catch net' stuff so that would not completely reset the calculator anyway when you clicked close and then Cancel. Improved this somewhat so all the dialogue stuff is initialised correctly and re-initialised when the user cancels - but it still needs to do something about retaining the dialogue contents. I am planning to use some sort of XML format in the final Save/Load routines (so advanced users/other programs can write their own calculation files and get DualCalc to run them ... thinks: and print/log the results, and 'chain' another calculation) but maybe a simple save/load of the strings in the dialogue would be better here. Meanwhile, back at the calculation, I copied over the starting section of the simple APR routine and produced a routine PROCtotalPays to sum the TAD (total advanced) and TAP for the loan data and calculate the TCC. Currently, at the end of the day, there are some snags:
Tuesday - took some time at home this morning to dig out and go right back to the original TRURATE code to see if I could spot the solution to the 365/6 Newton problem there. Nope, I modified it to do a 365/6 calculation and it promptly fell over. It seems - shock horror - Newton simply won't deal with this. The only option I can think of is to use Bisection in these cases. When I got into work I amended Newton's method to detect x going -ve and give up so Bisection could take over. Then Bisection fell over with the same log range error - Arrghhh!. It seems that the problem is that, to allow Bisection a wide sweep, I was using the range -1 to 2, introducing -ve x values again. So, I cut the range back to a more normal 0 to 2 and the program finally spat out an answer. What concerned me now was that the answer it produced, although clearly in the ball park, seemed to be quite a bit different from the answer produced by Newton's method using 365.25 periods, so I did a bit of experimenting:
Loan: £100
Although the fact that I could do this made it apparent that the program was not insisting on a relevant date for the 365/6 calculation, as it should, the close correspondence between the 366 day calculation and the 365/6 one made me more comfortable that it's doing the right calculation, but thankfully not the same calculation. Loads of minor problems when I tried to introduce the Relevant date into the calculation - but mainly me not paying enough attention to the times I should actually pass to the routines. I think it's all okay now, it unsurprisingly produces the same result as in the table above with a relevant date of 1/1/2004 - I wouldn't expect to see any difference over a 10-day period. So, a second calculation crossed off the list below. At some point I also added a catch net for the user clicking on the close icon - previously the program just closed down, now it asks of you're sure first - but it doesn't yet do anything to preserve the user's data, so they get back to an incomplete display. It at least needs to read the current data with FNcheck and write it back if the user cancels the close action. Also had the thought that the calculator might write the current calculation to disc when it closes and re-load it on startup, so the user comes back to the same state. This started me having thoughts about network use and multiple users (shudder - a lot of work in the DOS version). At present I'm working on the basis of one PC, one copy, although it might be possible to do something simple with a shortcut to a network copy and 'Start in' set locally so that the CSD (sorry a RISC OS term: 'currently selected directory') can be read on startup and all the load/save stuff done relative to there ... do this later! Started - again - to work on the next calculation (complex APR) and thought it would be a good idea if the array compaction routine returned the value of the last valid entry in the array - which the complex routine could use as a stop point in reading the data. However I discovered the compaction stuff was still a little broken and didn't cope with entries in the last element of the array. Need to fix this before proceeding. Monday - Further developed general routines for extra payments which handle 365/6 days too and hit quite a big snag. As I only have simple APR calculations available at present I tried a basic £100 loan repaid by 12 daily payments of £10 and it wouldn't work - Newton's method fell over with a 'log range' error because you can't raise -ve numbers to fractional powers and the first iteration was pulling up an x-factor of about -8 (it's normal between zero and one - yikes!) Spent a lot of time looking at this and checking back over the original formulae to see if I'd cocked something up - couldn't find the problem but tidied up the simple APR routines and incorporated the general extra routines FNextraPV() and FNextraDV() in the process. Also realised that I should use the extraPV/DV routines to deal with 365/6 days in the levelPV/DV routines. Gave up for a while and took another look at the business about displaying the current mode (I don't really like having the info down on the bottom line). Decided on - and implemented - an alternative where the significant buttons: Simple/Complex and APR/Rebate (also T/R); display the current status rather than their function - and these are in square brackets to indicate the distinction - haven't done this for the Calculate/Enter button though - I think it's pretty obvious how this works and doesn't need it. Still need to solve the Newton problem for 365/6.
Week commencing 15th November: Friday - More thinking than coding today, I have however written some more general APR levels routines (FNlevelPV and FNlevelDV) which will deal with any level, not just the first, AND will cope (I think) with 365/6 days. I've used these instead of FNequalPV and FNequalDV in the simple APR routines and all seems okay. Thursday - Only a bit of fiddling about today - added a 'Truncate/Round' button (just after the APR box, labelled T or R) and amended the greyMode() procedure to switch it. I'd sort of forgotten about truncation, it was linked to 365 days in the old programs and I think I was assuming it would be somehow here too? Think I've sorted out some of my concerns about date handling, albeit only in my head. Went through and tidied up the libraries a bit - and the 365/6 days routine. Also compiled another depressing list, this time of other bits of the program/project to be completed. This is quite similar to the button list but in order of priority: (the last two are deleted because I've decided not to do them) Wednesday - had some stuff to do on my 'real' job today so almost nothing changed. Decided I didn't like the mode indicators in the corners of the dialogue so I've combined them and put them in the bottom right corner. Started to look at an equal APR calculator for 365/6 days, this will probably have to be an entirely separate calculation routine which copes with both Newton's and the Bisection method, didn't get very far. Realised I had blocked off perfectly legitimate negative APR calculations, so I changed the error message to a warning with OK/Cancel buttons. Thought I might make a list of the calculations needed - just to depress myself (although to cheer myself up again, I've decided to cross out things here as I do 'em): [TO DO] Simple Actuarial Rebate - awaiting revised Regulations (This list has been halved now by removing duplicate 365/6 day entries - see Fri 26th Nov) Doh! Tuesday - Introduced the buttons mentioned yesterday and then got them into a (more) logical order. Sorted a glitch in the Simple data display (the Regular and Number values weren't written back and this lead me to looking again at the mode switching (parts of the dialogue being enabled/greyed out). Pretty much re-wrote this from scratch, this time ensuring that all the appropriate items are switched on/off for each mode combination - this enabled me to incorporate Calculate/Enter switching and remove the separate routines which did this - much 'cleaner' and more reliable now. Couldn't see any excuse not to start back on the calculations themselves now, but when I did I discovered there was something wrong with the Tidy routines. Although the array compaction worked fine for valid values dispersed across the array it didn't seem to want to remove invalid ones (zero advance or extra amounts, or zero length levels). While fixing this, I also implemented a vague idea I had a few days back that the display should go to the next free row (rather than back to the first row) after a Tidy. All seems to work now, so really no excuse not to go back to the calculations. I think my reluctance is, in part, because there are still some things I haven't cleared up in my mind, eg: how should the (currently implemented) Simple APR calculation react when the user chooses 365 or 366 as the Periods pa? Daily regular payments is probably a daft input anyway, so do I spend time writing a routine which calculates the APR (and Rebate) on an extras (one payment at a time) basis? It might make more sense to just get the program to say 'Hey! Daily repayments? Are you nuts? Ultimately, I think I am going to have to ask our lawyers how to approach this. As the user interface is provisionally finalised (is there such a thing?) now, I thought I'd end today's log with an image:
Monday - Not that much progress today but I did add a system where the Simple/Complex and APR/Rebate status is displayed in the bottom corners of the dialogue to give an independent indication of what's going on. Also finished the 'writing-back' stuff so each data item is put back in the dialogue in the right format as it's validated. There seemed to be something wrong with the APR calculation still, I was looking for examples where it would switch to Bisection and seemed to be finding them far too easily - and Newton's method was just going way off track (PV error = £???E24 or bigger) rather than just getting stuck. Deleted and then re-wrote the routines and it works now. Had a few more thoughts about the final look of the program and the facilities it might offer - came up with a provisional 'final' set of buttons/functions as follows (n/f = non-functional at present):
These seem a bit of a rag-bag at present and need more logical ordering. Our IT people confirmed that they block .exe files (but don't tell anyone) so I'll have to avoid sending them through the OFT mail system in future (or use my web mail account which seems to work fine). They were very helpful and have agreed to look at this so people are warned if their mail is altered and to consider the problem of mailing the final program.
Week commencing 8th November: Friday - implemented most of the list at the end of Thursday. There are now two buttons, initially labelled 'Simple' and 'APR' which toggle to 'Complex' and 'Rebate' when you click them. There is also a button which says Calculate while you're entering the data and 'Enter' while the results are displayed. Still tinkering with the validation/result reporting system. Sums of money now all right-adjusted and displayed to 2dp as soon as the program reads them, so the decimal points all line up, rates remain left adjusted and times centred to help distinguish them. I think I also need something to write back values to the combo-boxes after they are read and validated. Didn't bother to check for INVALID-> anywhere in a string, the point was to stop the program repeating it's own labelling, if the user's daft enough to actually type 'INVALID->' somewhere else themselves ... well duh. decided to put the latest version on the intranet so that other can keep track of it, mailed to let them know it's there. Re-incorporated the libraries with the program source for the time being - this makes it easier to track and correct errors and also means that the compiled version can be run from the intranet because it all downloads in one file. Have some doubts about the Simple/Complex and APR/Rebate buttons - just because they display what they will switch you to, not what you're currently doing - so, eg, wh | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||