170 likes | 329 Views
Drools Expert System with ECJ Genetic Algorithms. John Hurley, CS 461. Drools Expert + ECJ System. Combined my rules-based system for testing strategies with GA from ECJ Did not use GUI due to resource issues. Just used the GA functionality
E N D
Drools Expert System with ECJ Genetic Algorithms John Hurley, CS 461
Drools Expert + ECJ System • Combined my rules-based system for testing strategies with GA from ECJ • Did not use GUI due to resource issues. Just used the GA functionality • This still added up to a very bulky system for my four-year old laptop (1 gig RAM). Performance was difficult, but I still got good results • Developed rules for an individual investor with a single buy rule and a single short rule, not a metainvestor. My testing system can run a metainvestor, but this was too slow to run with the GA.
How This Could Be Useful • Transaction rules, including the learned ones, are expressed in Drools Rules language • Rules are separate from functionality • Easy for humans, including subject matter experts who are nonprogrammers, to understand • Learned rules can be easily studied by humans, applied to other testing logic, tweaked, compared to programmed rules • Additional functionality could be built for nonprogrammers to track the application of each easily-understood rule
Drools Expert + ECJ System What happens at runtime: • My setup code calls ECJ’s Evolve object, which loads stock data from file for each genome: • Evolve generates genome, calls fitness function • Fitness function calls my InvestorTester • InvestorTester converts genome from array of bools to if/then rules, writes the rules to a Drools rule file, saves file • InvestorTester adds Investor, the new rules file, a standard rule file, and necessary stock info to Drools runtime • Drools applies rules, which are implemented by Investor methods • InvestorTester returns the ending wealth to fitness function, which returns it to Evolve
Drools Expert + ECJ System At end of GA run: • Evolve reports best genome based on end-of-period wealth • User tests this genome again on training data (matches outcome of GA test but also generates a chart with comparison to buy and hold), then tests on test data
Drools Expert + ECJ System Data Split • 75% train, 25% test • Allocation is stored in the data file, so I can run repeated trials on the same data and preserve the data split from a particular training run to use in testing • Each day, a standard rule orders all investors to close all positions at the closing price • If the day is not in the current set (ie, if we are training and it is a test day or if we are testing and it is a train day) nothing else happens • If the day is in the current set, buy or short rules are executed • If day is in the set, we capture *tomorrow’s* price change, not today’s. In other words, the allocation is offset by one day. This is OK because we are interested in the *ending* value, not the particular days. Much simpler to implement than any other approach I could think of …
Drools Expert + ECJ System Limitation on investors
Drools Expert + ECJ System From Gen 0
Drools Expert + ECJ System From Gen 10, Same Run
Drools Expert + ECJ System From Gen 16, Same Run
Genome 1001111111111111001000101010111001 Training Data
Drools Expert + ECJ System package stockInvestment rule “clearout" salience 10 when inv: Investor() tick : TimeTick(tickNum:tickNum) stock: Stock(price:price) then inv.sellAll(price); inv.closeShort(price); end
Drools Expert + ECJ System package stockInvestment rule "GA Test Buy [Z@16caf43" salience 1 when Inv:InvGA() tick : TimeTick() stock: Stock(price:price && trainTest:trainTest&& lastTick:lastTick && maTen:maTen && maFifty:maFifty && maTwoHundred:maTwoHundred) eval(trainTest == "train") eval(lastTick == "up") (moving average tests all evaluated true for all values, ie ignore them) then inv.buyAll(price); end
Drools Expert + ECJ System rule "GA Test Sell [Z@16caf43" salience 1 when inv:InvGA() tick : TimeTick() stock: Stock(price:price && trainTest:trainTest&& lastTick:lastTick && maTen:maTen && maFifty:maFifty && maTwoHundred:maTwoHundred) eval(trainTest == "train") eval((price < maTen) == true) eval((price < maFifty) == true) eval((price < maTwoHundred) == true) eval((maTen < maTwoHundred) == true) eval((maFifty < maTwoHundred) == false) then inv.shortMax(price); end