├── .gitignore ├── README.md ├── Trading_Platform_GUI ├── AlgorithmicTrading.pro.user ├── AnalysisData.cpp ├── AnalysisData.h ├── AnalysisDisplays.cpp ├── AnalysisDisplays.h ├── CamelPushButton.cpp ├── CamelPushButton.h ├── DisplayAnalysis.cpp ├── DisplayAnalysis.h ├── DisplayAnalysis.ui ├── GlobalIncludes.h ├── Makefile ├── MyDateTableWidgetItem.h ├── MyTabWindow.h ├── MyTableWidgetItem.h ├── ParamAnalysisHelper.cpp ├── ParamAnalysisHelper.h ├── ParamSet.cpp ├── ParamSet.h ├── ParseCSVData.cpp ├── ParseCSVData.h ├── ParseInputCSVData.cpp ├── ParseInputCSVData.h ├── QuantPara.cpp ├── QuantPara.h ├── QuantitativeAnalysisDisplay.cpp ├── QuantitativeAnalysisDisplay.h ├── QuantitativeAnalysisDisplay.ui ├── ReturnsAnalysis.cpp ├── ReturnsAnalysis.h ├── SummaryForm.cpp ├── SummaryForm.h ├── TradeSimulator.cpp ├── TradeSimulator.h ├── icon.ico ├── iconise.rc ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── qt.config ├── resources.qrc ├── resources │ ├── analyse.jpg │ ├── barchart.png │ ├── displayanalysis.png │ ├── export_csv.png │ ├── file_csv.png │ ├── globe.gif │ ├── letterB.png │ ├── letterS.png │ ├── logo.png │ ├── run.png │ ├── run_program.gif │ └── terminal.gif ├── summaryform.ui └── tradesimulator.ui ├── src ├── CSVReader.cpp ├── CSVReader.h ├── CSVWriter.cpp ├── CSVWriter.h ├── GlobalIncludes.h ├── Logger.cpp ├── Logger.h ├── MomentumStrategy.cpp ├── MomentumStrategy.h ├── MomentumStrategyData.cpp ├── MomentumStrategyData.h ├── MutantFrogStrategy.cpp ├── MutantFrogStrategy.h ├── Params.cpp ├── Params.h ├── Strategy.cpp ├── Strategy.h ├── StrategyResult.cpp ├── StrategyResult.h ├── TradeDay.cpp ├── TradeDay.h ├── TradingInfluences.cpp ├── TradingInfluences.h ├── UnitTester.cpp ├── UnitTester.h ├── example.param ├── main.cpp ├── makefile └── makefile_linux └── tools ├── External Tester └── tester.py ├── Mass Data Generator └── generator.py └── Trock Equity Data Generator └── TrockEquityDataGen.c /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.swp 3 | *.swo 4 | *.o 5 | AlgorithmicTrading 6 | *.csv 7 | a.out 8 | *.log 9 | tools/External Tester/TrockEquityDataGen.exe 10 | tools/Trock Equity Data Generator/TrockEquityDataGen.exe 11 | tools/External Tester/trockAT.exe 12 | build-AlgorithmicTrading-Desktop_Qt_5_4_1_MinGW_32bit-Debug/ 13 | build-AlgorithmicTrading-Desktop_Qt_5_4_1_MinGW_32bit-Release/ 14 | *.pro 15 | *. 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Algorithmic Trading Application 2 | ========= 3 | **This was part of the project outcome for the SENG3011 course in Semester 1, 2015** 4 | 5 | Algorithm modules designed to make money on the equity market. 6 | The Trock Testing Platform is a GUI which can utilise stragegy modules made by ourselves or other teams. 7 | The Testing Platform features quantitive analysis, the ability to run different stragegy modules, the ability to analyse order CSV files, and much more. 8 | 9 | The Testing Platform was written using Qt and is cross compatible with Windows, MAC OS and Linux operating systems. 10 | Both the Testing Platform and backend were written in C++ with speed being a top priority. 11 | The latest iteration of the software is incredibly effecient and can analyse huge input files within seconds. 12 | 13 | Images 14 | ----- 15 | 16 |

Analytics Summary:

17 | 18 | ![Analytics Summary](/../screenshots/screenshots/analysis%20summary.png?raw=true "Analytics Summary") 19 | 20 |

Analysis Tab:

21 | 22 | ![Analysis Tab](/../screenshots/screenshots/analysis%20tab.png?raw=true "Analysis Tab") 23 | 24 |

Graph View:

25 | 26 | ![Graph View](/../screenshots/screenshots/graph%20view.png?raw=true "Graph View") 27 | 28 |

Quantitative Analysis Tab:

29 | 30 | ![Quantitative Analysis Tab](/../screenshots/screenshots/quantitative%20analysis%20tab.png?raw=true "Quantitative Analysis Tab") 31 | 32 |

Quantitative Analysis:

33 | 34 | ![Quantitative Analysis](/../screenshots/screenshots/quantitative%20analysis.png?raw=true "Quantitative Analysis") 35 | 36 |

Run Strategy:

37 | 38 | ![Run Strategy](/../screenshots/screenshots/run%20strategy.png?raw=true "Run Strategy") 39 | 40 |

Trade Simulator Tab:

41 | 42 | ![Trade Simulator Tab](/../screenshots/screenshots/trade%20simulator%20tab.png?raw=true "Trade Simulator Tab") 43 | 44 |

Trade Simulator:

45 | 46 | ![Trade Simulator](/../screenshots/screenshots/trade%20simulator.png?raw=true "Trade Simulator") 47 | 48 | 49 | License 50 | ---- 51 | Free to use. 52 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/AlgorithmicTrading.pro.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EnvironmentId 7 | {141aedd6-cedd-4afc-bf04-1ad8e1c854d0} 8 | 9 | 10 | ProjectExplorer.Project.ActiveTarget 11 | 0 12 | 13 | 14 | ProjectExplorer.Project.EditorSettings 15 | 16 | true 17 | false 18 | true 19 | 20 | Cpp 21 | 22 | CppGlobal 23 | 24 | 25 | 26 | QmlJS 27 | 28 | QmlJSGlobal 29 | 30 | 31 | 2 32 | UTF-8 33 | false 34 | 4 35 | false 36 | 80 37 | true 38 | true 39 | 1 40 | true 41 | false 42 | 0 43 | true 44 | 0 45 | 8 46 | true 47 | 1 48 | true 49 | true 50 | true 51 | false 52 | 53 | 54 | 55 | ProjectExplorer.Project.PluginSettings 56 | 57 | 58 | 59 | ProjectExplorer.Project.Target.0 60 | 61 | Desktop Qt 5.4.1 MinGW 32bit 62 | Desktop Qt 5.4.1 MinGW 32bit 63 | qt.54.win32_mingw491_kit 64 | 0 65 | 0 66 | 0 67 | 68 | O:/Dropbox/Github/Algorithmic-Trading/build-AlgorithmicTrading-Desktop_Qt_5_4_1_MinGW_32bit-Debug 69 | 70 | 71 | true 72 | qmake 73 | 74 | QtProjectManager.QMakeBuildStep 75 | false 76 | true 77 | 78 | false 79 | false 80 | 81 | 82 | true 83 | Make 84 | 85 | Qt4ProjectManager.MakeStep 86 | 87 | false 88 | 89 | 90 | 91 | 2 92 | Build 93 | 94 | ProjectExplorer.BuildSteps.Build 95 | 96 | 97 | 98 | true 99 | Make 100 | 101 | Qt4ProjectManager.MakeStep 102 | 103 | true 104 | clean 105 | 106 | 107 | 1 108 | Clean 109 | 110 | ProjectExplorer.BuildSteps.Clean 111 | 112 | 2 113 | false 114 | 115 | Debug 116 | 117 | Qt4ProjectManager.Qt4BuildConfiguration 118 | 2 119 | true 120 | 121 | 122 | O:/Dropbox/Github/Algorithmic-Trading/build-AlgorithmicTrading-Desktop_Qt_5_4_1_MinGW_32bit-Release 123 | 124 | 125 | true 126 | qmake 127 | 128 | QtProjectManager.QMakeBuildStep 129 | false 130 | true 131 | 132 | false 133 | false 134 | 135 | 136 | true 137 | Make 138 | 139 | Qt4ProjectManager.MakeStep 140 | 141 | false 142 | 143 | 144 | 145 | 2 146 | Build 147 | 148 | ProjectExplorer.BuildSteps.Build 149 | 150 | 151 | 152 | true 153 | Make 154 | 155 | Qt4ProjectManager.MakeStep 156 | 157 | true 158 | clean 159 | 160 | 161 | 1 162 | Clean 163 | 164 | ProjectExplorer.BuildSteps.Clean 165 | 166 | 2 167 | false 168 | 169 | Release 170 | 171 | Qt4ProjectManager.Qt4BuildConfiguration 172 | 0 173 | true 174 | 175 | 2 176 | 177 | 178 | 0 179 | Deploy 180 | 181 | ProjectExplorer.BuildSteps.Deploy 182 | 183 | 1 184 | Deploy locally 185 | 186 | ProjectExplorer.DefaultDeployConfiguration 187 | 188 | 1 189 | 190 | 191 | 192 | false 193 | false 194 | false 195 | false 196 | true 197 | 0.01 198 | 10 199 | true 200 | 1 201 | 25 202 | 203 | 1 204 | true 205 | false 206 | true 207 | valgrind 208 | 209 | 0 210 | 1 211 | 2 212 | 3 213 | 4 214 | 5 215 | 6 216 | 7 217 | 8 218 | 9 219 | 10 220 | 11 221 | 12 222 | 13 223 | 14 224 | 225 | 2 226 | 227 | AlgorithmicTrading 228 | 229 | Qt4ProjectManager.Qt4RunConfiguration:O:/Dropbox/Github/Algorithmic-Trading/Trading_Platform_GUI/AlgorithmicTrading.pro 230 | 231 | AlgorithmicTrading.pro 232 | false 233 | false 234 | 235 | 3768 236 | false 237 | true 238 | false 239 | false 240 | true 241 | 242 | 1 243 | 244 | 245 | 246 | ProjectExplorer.Project.TargetCount 247 | 1 248 | 249 | 250 | ProjectExplorer.Project.Updater.FileVersion 251 | 18 252 | 253 | 254 | Version 255 | 18 256 | 257 | 258 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/AnalysisData.cpp: -------------------------------------------------------------------------------- 1 | #include "AnalysisData.h" 2 | 3 | namespace std { 4 | 5 | AnalysisData::AnalysisData(string company) : company(company) { 6 | totalDaysTrading = 0; 7 | priceLow = -1; 8 | priceHigh = -1; 9 | } 10 | 11 | AnalysisData::~AnalysisData() { 12 | 13 | } 14 | 15 | void AnalysisData::addNextTradeData(signal tradeSignal, string date, double price, int volume) { 16 | TradeData trade; 17 | trade.date = date; 18 | trade.tradeSignal = tradeSignal; 19 | trade.price = price; 20 | if (price > priceHigh || priceHigh == -1) { 21 | priceHigh = price; 22 | } else if (price < priceLow || priceLow == -1) { 23 | priceLow = price; 24 | } 25 | if (tradeDataAvailable() == 0) { 26 | trade.tradeDayOffset = 0; 27 | totalDaysTrading = 1; 28 | } else { 29 | trade.tradeDayOffset = daysDifference(lastTradeDate(), trade.date) + totalDaysTrading - 1; 30 | totalDaysTrading = trade.tradeDayOffset + 1; //offset to lastest day + 1 31 | } 32 | tradeData.push_back(trade); 33 | } 34 | 35 | int AnalysisData::tradeDataAvailable() { 36 | return tradeData.size(); 37 | } 38 | 39 | string AnalysisData::firstTradeDate() { 40 | return tradeData[0].date; 41 | } 42 | 43 | string AnalysisData::lastTradeDate() { 44 | return tradeData[tradeDataAvailable() - 1].date; 45 | } 46 | 47 | string AnalysisData::getCompany() { 48 | return company; 49 | } 50 | 51 | int AnalysisData::daysTrading() { 52 | return totalDaysTrading; 53 | } 54 | 55 | double AnalysisData::highestPrice() { 56 | return priceHigh; 57 | } 58 | 59 | double AnalysisData::lowestPrice() { 60 | return priceLow; 61 | } 62 | 63 | int AnalysisData::daysDifference(string dateFrom, string dateTo) { 64 | 65 | Date from = Helper::parseDate(dateFrom); 66 | Date to = Helper::parseDate(dateTo); 67 | 68 | if (from.day == -1 || to.day == -1 || from.month == -1 || to.month == -1 || from.year == -1 || to.year == -1) { 69 | return -1; //error, date parse failed 70 | } 71 | 72 | int diff = 0; 73 | 74 | while (from.year < to.year || (from.year == to.year && (from.month < to.month || (from.month == to.month && from.day < to.day)) ) ) { 75 | diff++; 76 | from.day++; 77 | if (from.day > Helper::daysInMonth(from.month, from.year)) { 78 | from.day = 1; 79 | from.month++; 80 | if (from.month > 12) { 81 | from.month = 1; 82 | from.year++; 83 | } 84 | } 85 | } 86 | 87 | return diff; 88 | } 89 | 90 | 91 | } 92 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/AnalysisData.h: -------------------------------------------------------------------------------- 1 | #ifndef ANALYSISDATA_H 2 | #define ANALYSISDATA_H 3 | 4 | #include "GlobalIncludes.h" 5 | 6 | #include 7 | #include 8 | 9 | 10 | namespace std { 11 | 12 | enum signal { 13 | BUY, 14 | SELL 15 | }; 16 | 17 | struct TradeData { 18 | signal tradeSignal; 19 | string date; 20 | double price; 21 | int tradeDayOffset; //days from the start of trading 22 | }; 23 | 24 | 25 | class AnalysisData 26 | { 27 | 28 | private: 29 | vector tradeData; 30 | string company; 31 | int totalDaysTrading; 32 | double priceLow; 33 | double priceHigh; 34 | 35 | int daysDifference(string dateFrom, string dateTo); 36 | 37 | public: 38 | AnalysisData(string company); 39 | ~AnalysisData(); 40 | 41 | void addNextTradeData(signal tradeSignal, string date, double price, int volume); 42 | 43 | int tradeDataAvailable(); 44 | inline TradeData getData(int index) {return tradeData[index];} 45 | 46 | string firstTradeDate(); 47 | string lastTradeDate(); 48 | 49 | int daysTrading(); //total days, first - last trade date 50 | 51 | string getCompany(); 52 | 53 | double highestPrice(); 54 | double lowestPrice(); 55 | 56 | }; 57 | 58 | } 59 | 60 | #endif // ANALYSISDATA_H 61 | 62 | 63 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/AnalysisDisplays.cpp: -------------------------------------------------------------------------------- 1 | #include "AnalysisDisplays.h" 2 | #include "DisplayAnalysis.h" 3 | #include "SummaryForm.h" 4 | #include "MyTabWindow.h" 5 | 6 | #include "mainwindow.h" 7 | #include "ui_mainwindow.h" 8 | 9 | AnalysisDisplays* __analysisDisplays = nullptr; 10 | 11 | AnalysisDisplays::AnalysisDisplays() 12 | { 13 | currentDisplayId = 0; 14 | parseCSV = nullptr; 15 | } 16 | 17 | AnalysisDisplays::~AnalysisDisplays() 18 | { 19 | if (parseCSV != nullptr) delete parseCSV; 20 | } 21 | 22 | AnalysisDisplays *AnalysisDisplays::instance() { 23 | if (__analysisDisplays == nullptr) { 24 | __analysisDisplays = new AnalysisDisplays(); 25 | } 26 | return __analysisDisplays; 27 | } 28 | 29 | 30 | void AnalysisDisplays::showCheckList(std::string csvFile, QListWidget* lw, QWidget *parent) { 31 | 32 | parseCSV = new std::ParseCSVData(csvFile); 33 | 34 | //Add checkboxes to list for each company 35 | for (std::string eqType : parseCSV->getAllEquityTypes()) { 36 | const QString itemName = eqType.c_str(); 37 | QListWidgetItem *item = new QListWidgetItem(itemName, lw); 38 | item->setFlags(item->flags() | Qt::ItemIsUserCheckable); // set checkable flag 39 | item->setCheckState(Qt::Unchecked); // AND initialize check state 40 | lw->addItem(item); 41 | listItems.push_back(item); 42 | } 43 | 44 | 45 | } 46 | 47 | vector> AnalysisDisplays::exportAnalysisData(){ 48 | vector eqTypeList; 49 | for (QListWidgetItem *wi: listItems) { 50 | if(wi->checkState()) { 51 | eqTypeList.push_back(wi->text().toStdString()); 52 | } 53 | } 54 | return SummaryForm::export_Summary(this->parseCSV, eqTypeList); 55 | } 56 | void AnalysisDisplays::showAnalysisDisplays(QWidget *parent) { 57 | 58 | QMainWindow *mw = new QMainWindow(parent); 59 | 60 | mw->setWindowTitle("Equity Strategy Analysis"); 61 | mw->setMinimumSize(750, 700); 62 | 63 | MyTabWidget *tabw = new MyTabWidget(mw, this->parseCSV); 64 | mw->setCentralWidget(tabw); 65 | 66 | //Load summary tab 67 | SummaryForm *summary = new SummaryForm(tabw); 68 | std::string summaryText = "Summary"; 69 | tabw->addTab(summary, summaryText.c_str()); 70 | tabw->addEqType(summaryText); 71 | 72 | //Create vector of checked equities 73 | vector eqTypeList; 74 | for (QListWidgetItem *wi: listItems) { 75 | if (wi->checkState()) { 76 | eqTypeList.push_back(wi->text().toStdString()); 77 | } 78 | } 79 | 80 | //Set total returns 81 | summary->setTotalNetReturns(this->parseCSV, eqTypeList); 82 | summary->show(); 83 | 84 | //Load company tabs 85 | for (QListWidgetItem *wi: listItems) { 86 | if (wi->checkState()) { 87 | std::string eqType = wi->text().toStdString(); 88 | 89 | tabw->addEqType(eqType); 90 | 91 | DisplayAnalysis *dw = new DisplayAnalysis(); 92 | 93 | displays[currentDisplayId] = dw; 94 | 95 | //Add this tab to tab widget 96 | tabw->addTab(dw, eqType.c_str()); 97 | 98 | dw->setDisplayId(currentDisplayId); 99 | currentDisplayId++; 100 | } 101 | } 102 | 103 | //Show the main window 104 | mw->show(); 105 | } 106 | 107 | void AnalysisDisplays::analyzeCSVOutput(std::string csvFile, QWidget *parent) { 108 | 109 | std::ParseCSVData parseCSV = std::ParseCSVData(csvFile); 110 | 111 | if (parseCSV.getAllEquityTypes().size() == 0) { 112 | QMessageBox::question(parent, "No Equity Trades", "The strategy suggested no equity trades.", QMessageBox::Ok); 113 | return; 114 | } 115 | 116 | QMainWindow *mw = new QMainWindow(parent); 117 | 118 | mw->setWindowTitle("Equity Strategy Analysis"); 119 | mw->setMinimumSize(750, 700); 120 | 121 | QTabWidget *tabw = new QTabWidget(mw); 122 | mw->setCentralWidget(tabw); 123 | 124 | std::ParseCSVData tmpParseCSV = std::ParseCSVData(csvFile); 125 | 126 | for (std::string eqType : tmpParseCSV.getAllEquityTypes()) { 127 | 128 | DisplayAnalysis *dw = new DisplayAnalysis(); 129 | 130 | displays[currentDisplayId] = dw; 131 | 132 | //Add this tab to tab widget 133 | tabw->addTab(dw, eqType.c_str()); 134 | 135 | dw->setDisplayId(currentDisplayId); 136 | currentDisplayId++; 137 | dw->show(); 138 | 139 | dw->displayAnalysis(tmpParseCSV.getDataForEquityType(eqType)); 140 | } 141 | 142 | //Show the main window 143 | mw->show(); 144 | } 145 | 146 | void AnalysisDisplays::displayClosing(long displayId) { 147 | if (displays.find(displayId) != displays.end()) { 148 | DisplayAnalysis *display = displays[displayId]; 149 | delete display; 150 | displays.erase(displayId); 151 | } 152 | } 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/AnalysisDisplays.h: -------------------------------------------------------------------------------- 1 | #ifndef ANALYSISDISPLAYS_H 2 | #define ANALYSISDISPLAYS_H 3 | 4 | #include "DisplayAnalysis.h" 5 | #include "ParseCSVData.h" 6 | #include "GlobalIncludes.h" 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | class AnalysisDisplays 14 | { 15 | 16 | private: 17 | std::map displays; 18 | std::vector listItems; 19 | std::ParseCSVData *parseCSV; 20 | long currentDisplayId; 21 | 22 | public: 23 | AnalysisDisplays(); 24 | ~AnalysisDisplays(); 25 | static AnalysisDisplays *instance(); 26 | vector> exportAnalysisData(); 27 | 28 | inline std::vector getListItems() { return listItems; } 29 | void analyzeCSVOutput(std::string csvFile, QWidget *parent); 30 | void showAnalysisDisplays(QWidget *parent); 31 | void showCheckList(std::string csvFile, QListWidget* lw, QWidget *parent); 32 | void displayClosing(long displayId); 33 | }; 34 | 35 | #endif // ANALYSISDISPLAYS_H 36 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/CamelPushButton.cpp: -------------------------------------------------------------------------------- 1 | #include "CamelPushButton.h" 2 | 3 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/CamelPushButton.h: -------------------------------------------------------------------------------- 1 | #ifndef CAMELPUSHBUTTON_H 2 | #define CAMELPUSHBUTTON_H 3 | 4 | #include 5 | 6 | class CamelPushButton : public QPushButton 7 | { 8 | public: 9 | void *hump; 10 | }; 11 | 12 | #endif // CAMELPUSHBUTTON_H 13 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/DisplayAnalysis.cpp: -------------------------------------------------------------------------------- 1 | #include "DisplayAnalysis.h" 2 | #include "ui_DisplayAnalysis.h" 3 | #include "MyTableWidgetItem.h" 4 | #include "MyDateTableWidgetItem.h" 5 | #include "AnalysisDisplays.h" 6 | 7 | DisplayAnalysis::DisplayAnalysis(QWidget *parent) : 8 | QWidget(parent), ui(new Ui::DisplayAnalysis) 9 | { 10 | this->ui->setupUi(this); 11 | scene = nullptr; 12 | displayId = -1; 13 | } 14 | 15 | void DisplayAnalysis::setDisplayId(long displayId) { 16 | this->displayId = displayId; 17 | } 18 | 19 | void DisplayAnalysis::closeEvent(QCloseEvent *event) { 20 | QWidget::closeEvent(event); 21 | AnalysisDisplays::instance()->displayClosing(displayId); 22 | } 23 | 24 | void DisplayAnalysis::displayGraphAnalysis(std::AnalysisData *data) { 25 | 26 | QFont titleFont = QFont(); 27 | titleFont.setBold(true); 28 | QFont normalFont = QFont(); 29 | normalFont.setBold(false); 30 | 31 | 32 | double daySize = 7.0; 33 | double chartHeight = 240.0; 34 | 35 | if (scene != nullptr) 36 | delete scene; 37 | scene = new QGraphicsScene(); 38 | 39 | double extraWidth = 150.0 + 50.0; 40 | double extraBase = 30.0; 41 | 42 | double shiftX = - ((-daySize) * data->daysTrading() / 2 - extraWidth/2.0);//50.0; 43 | double shiftY = 0.0; 44 | 45 | scene->setSceneRect(0, shiftY - (chartHeight/2.0), daySize * data->daysTrading() + extraWidth, chartHeight + extraBase); 46 | 47 | QPen pen; 48 | 49 | //draw y axis label "Equity Price" 50 | double yAxisLabelY = shiftY - 70.0; 51 | double yAxisLabelX = shiftX + (-daySize) * data->daysTrading() / 2 - 92.0;//150.0; 52 | scene->addText("P\nr\ni\nc\ne", titleFont)->setPos(yAxisLabelX, yAxisLabelY); 53 | 54 | //draw x axis label "date" 55 | double xAxisLabelY = shiftY + chartHeight/2.0 + 30.0; 56 | double xAxisLabelX = shiftX + (-daySize) * data->daysTrading() / 2 + 50.0; 57 | scene->addText("Date", titleFont)->setPos(xAxisLabelX, xAxisLabelY); 58 | 59 | 60 | double startX = shiftX + (-daySize) * data->daysTrading() / 2 + daySize/2; 61 | double startY = shiftY + chartHeight/2.0 + daySize + 4; 62 | 63 | 64 | //draw price markers 65 | double markerPriceX = startX - 70.0; 66 | int numPriceMarkers = 6; 67 | 68 | double percentUsed = (floor(data->highestPrice() - ceil(data->lowestPrice())) / (data->highestPrice() - data->lowestPrice())); 69 | 70 | if (percentUsed <= 0.0) { 71 | for (int i = 0; i != numPriceMarkers; ++i) { 72 | double percentMarker = static_cast(i) / (static_cast(numPriceMarkers) - 1.0); 73 | double markerPriceY = shiftY + chartHeight/2.0 - chartHeight * percentMarker + daySize/2.0; 74 | scene->addText(QString::fromStdString(std::Helper::formatPrice(percentMarker * (data->highestPrice() - data->lowestPrice()) + data->lowestPrice())), normalFont)->setPos(markerPriceX, markerPriceY); 75 | scene->addLine(markerPriceX, markerPriceY, markerPriceX + daySize * data->daysTrading() + extraWidth, markerPriceY, pen); 76 | } 77 | 78 | } else { 79 | 80 | for (int i = 0; i != numPriceMarkers + 1; ++i) { 81 | double additionOfPercentForSmoothness = 1.0 - (data->highestPrice() - ceil(data->lowestPrice())) / (data->highestPrice() - data->lowestPrice()); 82 | double percentMarkerIncr = percentUsed * (static_cast(1.0) / (static_cast(numPriceMarkers) - 1.0)); 83 | if (additionOfPercentForSmoothness >= percentMarkerIncr) { 84 | additionOfPercentForSmoothness -= percentMarkerIncr; 85 | } 86 | double percentMarker = percentUsed * (static_cast(i) / (static_cast(numPriceMarkers) - 1.0)) + additionOfPercentForSmoothness; 87 | 88 | double markerPriceY = shiftY + chartHeight/2.0 - chartHeight * percentMarker + daySize/2.0; 89 | scene->addText(QString::fromStdString(std::Helper::formatPrice(percentMarker * (data->highestPrice() - data->lowestPrice()) + data->lowestPrice())), normalFont)->setPos(markerPriceX, markerPriceY); 90 | scene->addLine(markerPriceX, markerPriceY, markerPriceX + daySize * data->daysTrading() + extraWidth, markerPriceY, pen); 91 | } 92 | 93 | } 94 | 95 | //draw dates and lines 96 | if (data->tradeDataAvailable() > 0) { 97 | std::TradeData firstTrade = data->getData(0); 98 | 99 | int daysBetweenDateMarkers = 14; 100 | int dayUpto = 0; 101 | std::Date currDate = std::Helper::parseDate(firstTrade.date); 102 | 103 | 104 | while (dayUpto < data->daysTrading()) { 105 | scene->addLine(startX + dayUpto*daySize, startY, startX + dayUpto*daySize, -startY, pen); 106 | scene->addText(QString::fromStdString(std::Helper::dateString(currDate)), normalFont)->setPos(startX + dayUpto*daySize - 9.0, startY); 107 | currDate = std::Helper::addDays(currDate, daysBetweenDateMarkers); 108 | dayUpto += daysBetweenDateMarkers; 109 | } 110 | 111 | } 112 | 113 | int startOfDaysPos = (-daySize) * data->daysTrading() / 2; 114 | 115 | double prevX, prevY; 116 | bool hasPreviousPos = false; 117 | 118 | for (int i = 0; i < data->tradeDataAvailable(); ++i) { 119 | std::TradeData trade = data->getData(i); 120 | 121 | double pricePercentToMax = (trade.price - data->lowestPrice()) / (data->highestPrice() - data->lowestPrice()); 122 | 123 | QBrush brush = QBrush(Qt::blue); 124 | if (trade.tradeSignal == std::SELL) { 125 | brush = QBrush(Qt::green); 126 | } 127 | 128 | scene->addEllipse(shiftX + startOfDaysPos + daySize * trade.tradeDayOffset, shiftY + chartHeight/2.0 - chartHeight * pricePercentToMax, daySize, daySize, pen, brush); 129 | 130 | double thisX = shiftX + startOfDaysPos + daySize * trade.tradeDayOffset + daySize/2.0; 131 | double thisY = shiftY + chartHeight/2.0 - chartHeight * pricePercentToMax + daySize/2.0; 132 | 133 | if (hasPreviousPos) { 134 | scene->addLine(thisX, thisY, prevX, prevY, pen); 135 | } 136 | 137 | hasPreviousPos = true; 138 | prevX = thisX; 139 | prevY = thisY; 140 | } 141 | 142 | ui->graphicsGraphDisplay->setScene(scene); 143 | ui->graphicsGraphDisplay->setRenderHints( QPainter::Antialiasing ); 144 | } 145 | 146 | 147 | void DisplayAnalysis::displayReturnsAnalysis(std::AnalysisData *data) { 148 | 149 | //Prepare the table 150 | ui->returnsAnalysis->setColumnCount(4); //for the four headings: buy,sell,date,and return 151 | ui->returnsAnalysis->verticalHeader()->setVisible(false); //hide line numbers 152 | ui->returnsAnalysis->setHorizontalHeaderLabels(QString("Buy-Sell Pair;Date;Return Value;Return %").split(";")); //insert column names 153 | 154 | //adjusting header sizes 155 | ui->returnsAnalysis->horizontalHeader()->resizeSection(0,215); 156 | ui->returnsAnalysis->horizontalHeader()->resizeSection(1,170); 157 | ui->returnsAnalysis->horizontalHeader()->resizeSection(2,145); 158 | ui->returnsAnalysis->horizontalHeader()->resizeSection(3,155); 159 | 160 | 161 | //maintain queues of trades, one for buy and one for sell 162 | // int is for maintaining which one came first 163 | vector> buy_trades; 164 | vector> sell_trades; 165 | 166 | //maintain total return percentage 167 | double net_return_value = 0; 168 | double net_return_perc = 0; 169 | 170 | //read the trade orders line by line 171 | for (int i = 0; i < data->tradeDataAvailable(); i++) { 172 | //Prepare some variables 173 | string buySellPair; //details buy and sell price 174 | string date; //when the buy-sell / sell-buy pair occurs 175 | string returnValue; //the numeric return value 176 | string returnPerc; //the percentage return value 177 | 178 | //load the vectors as appropriate 179 | if (data->getData(i).tradeSignal == BUY) { 180 | buy_trades.push_back(tuple(data->getData(i),i)); 181 | } else { 182 | sell_trades.push_back(tuple(data->getData(i),i)); 183 | } 184 | 185 | //Determine whether there is a buy-sell / sell-buy pair 186 | if (buy_trades.size() > 0 && sell_trades.size() > 0) { 187 | tuple buy_trade = buy_trades.front(); 188 | tuple sell_trade = sell_trades.front(); 189 | 190 | char buySellPairBuffer[50]; //for converting buy-sell values into a string 191 | 192 | if (get<1>(sell_trade) > get<1>(buy_trade)) { //a buy-sell pair 193 | 194 | //Construct buy-sell pair string 195 | sprintf(buySellPairBuffer,"Buy: $%.2lf, Sell: $%.2lf",get<0>(buy_trade).price,get<0>(sell_trade).price); 196 | buySellPair = std::string(buySellPairBuffer); 197 | 198 | //Construct Date string 199 | date.append(get<0>(sell_trade).date.c_str()); 200 | 201 | } else { //a sell-buy pair 202 | 203 | //Construct buy-sell pair string 204 | sprintf(buySellPairBuffer,"Sell: $%.2lf, Buy: $%.2lf",get<0>(sell_trade).price,get<0>(buy_trade).price); 205 | buySellPair = std::string(buySellPairBuffer); 206 | 207 | //Construct Date string 208 | date.append(get<0>(buy_trade).date.c_str()); 209 | 210 | } 211 | 212 | //Calculate and construct return value string 213 | double return_value =(get<0>(sell_trade).price - get<0>(buy_trade).price); 214 | char returnValueBuffer[50]; 215 | if (return_value < 0) { 216 | sprintf(returnValueBuffer,"-$%.2lf",return_value * (-1)); 217 | } else { 218 | sprintf(returnValueBuffer,"$%.2lf",return_value); 219 | } 220 | returnValue = std::string(returnValueBuffer); 221 | 222 | //Calculate and construct return percentage string 223 | double return_perc = (get<0>(sell_trade).price - get<0>(buy_trade).price) * 100 / get<0>(buy_trade).price; 224 | char returnPercBuffer[50]; 225 | sprintf(returnPercBuffer,"%.2lf",return_perc); 226 | returnPerc = std::string(returnPercBuffer); 227 | returnPerc.append("%"); 228 | 229 | //Insert results into table 230 | insertRowIntoReturnsAnalysis(buySellPair, date, returnValue, returnPerc); 231 | 232 | //update total return value and percentage 233 | net_return_value += return_value; 234 | net_return_perc += return_perc; 235 | 236 | //Remove the first trades from both queues 237 | buy_trades.erase(buy_trades.begin(),buy_trades.begin()+1); 238 | sell_trades.erase(sell_trades.begin(),sell_trades.begin()+1); 239 | } 240 | } 241 | 242 | //Display net return 243 | QString net_return_perc_str; 244 | net_return_perc_str.append(QString::number(net_return_perc)); 245 | net_return_perc_str.append("%"); 246 | ui->net_return_value_label->setText(net_return_perc_str); 247 | 248 | } 249 | 250 | void DisplayAnalysis::insertRowIntoReturnsAnalysis(std::string buySellPair, 251 | std::string date, 252 | std::string returnValue, 253 | std::string returnPerc) { 254 | 255 | //increase table rows by 1 256 | int currRows = ui->returnsAnalysis->rowCount(); 257 | ui->returnsAnalysis->setRowCount(currRows + 1); 258 | 259 | 260 | QTableWidgetItem* col0 = new QTableWidgetItem(QString::fromStdString(buySellPair), QTableWidgetItem::Type); 261 | col0->setFlags(col0->flags() ^ Qt::ItemIsEditable); 262 | col0->setTextAlignment(Qt::AlignHCenter); 263 | ui->returnsAnalysis->setItem(currRows,0, col0); 264 | 265 | MyDateTableWidgetItem* col1 = new MyDateTableWidgetItem(QString::fromStdString(date)); 266 | col1->setFlags(col1->flags() ^ Qt::ItemIsEditable); 267 | col1->setTextAlignment(Qt::AlignHCenter); 268 | ui->returnsAnalysis->setItem(currRows, 1, col1); 269 | 270 | 271 | MyTableWidgetItem* col2 = new MyTableWidgetItem(QString::fromStdString(returnValue)); 272 | col2->setFlags(col2->flags() ^ Qt::ItemIsEditable); 273 | col2->setTextAlignment(Qt::AlignHCenter); 274 | ui->returnsAnalysis->setItem(currRows, 2, col2); 275 | 276 | MyTableWidgetItem* col3 = new MyTableWidgetItem(QString::fromStdString(returnPerc)); 277 | col3->setFlags(col2->flags() ^ Qt::ItemIsEditable); 278 | col3->setTextAlignment(Qt::AlignHCenter); 279 | ui->returnsAnalysis->setItem(currRows, 3, col3); 280 | } 281 | 282 | 283 | void DisplayAnalysis::displayAnalysis(std::AnalysisData *data) { 284 | 285 | this->setWindowTitle(QString::fromStdString("Equity Strategy Analysis (" + data->getCompany() + ")")); 286 | this->displayGraphAnalysis(data); 287 | this->displayReturnsAnalysis(data); 288 | } 289 | 290 | DisplayAnalysis::~DisplayAnalysis() 291 | { 292 | if (scene != nullptr) 293 | delete scene; 294 | } 295 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/DisplayAnalysis.h: -------------------------------------------------------------------------------- 1 | #ifndef DISPLAYANALYSIS_H 2 | #define DISPLAYANALYSIS_H 3 | 4 | #include "GlobalIncludes.h" 5 | 6 | #include "AnalysisData.h" 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | using namespace std; //for vectors 18 | 19 | namespace Ui { 20 | class DisplayAnalysis; 21 | } 22 | 23 | class DisplayAnalysis : public QWidget 24 | { 25 | Q_OBJECT 26 | 27 | public: 28 | explicit DisplayAnalysis(QWidget *parent = 0); 29 | ~DisplayAnalysis(); 30 | 31 | void setDisplayId(long displayId); 32 | void displayAnalysis(std::AnalysisData *data); 33 | 34 | void displayGraphAnalysis(std::AnalysisData *data); 35 | void displayReturnsAnalysis(std::AnalysisData *data); 36 | 37 | void insertRowIntoReturnsAnalysis(std::string buySellPair, 38 | std::string date, 39 | std::string returnValue, 40 | std::string returnPerc); 41 | 42 | virtual void closeEvent(QCloseEvent *event); 43 | 44 | private: 45 | Ui::DisplayAnalysis *ui; 46 | QGraphicsScene *scene; 47 | long displayId; 48 | }; 49 | 50 | #endif // DISPLAYANALYSIS_H 51 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/DisplayAnalysis.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | DisplayAnalysis 4 | 5 | 6 | 7 | 0 8 | 0 9 | 750 10 | 652 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | Form 21 | 22 | 23 | 24 | 25 | 26 | 27 | 0 28 | 0 29 | 30 | 31 | 32 | true 33 | 34 | 35 | 36 | 37 | 0 38 | 0 39 | 726 40 | 628 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | true 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 75 63 | true 64 | 65 | 66 | 67 | Net Return: 68 | 69 | 70 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | <span style="color:blue">Blue - Buy</span> 105 | 106 | 107 | 108 | 109 | 110 | 111 | <html><head/><body><p><span style=" color:#009940;">Green - Sell</span></p></body></html> 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/GlobalIncludes.h: -------------------------------------------------------------------------------- 1 | // 2 | // GlobalIncludes.h 3 | // Algorithmic Trading COMP3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Revitpo. All rights reserved. 7 | // 8 | 9 | 10 | #ifndef __Algorithmic_Trading__GlobalIncludes__ 11 | #define __Algorithmic_Trading__GlobalIncludes__ 12 | 13 | #define ERR_FATAL(info) printf(info);exit(1) 14 | #define ERR(info) printf(info) 15 | 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace std { 25 | 26 | struct Date { 27 | int day; 28 | int month; 29 | int year; 30 | }; 31 | 32 | class Helper { 33 | public: 34 | 35 | //trim functions from http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring 36 | //self explainitory 37 | 38 | // trim from start 39 | static inline std::string <rim(std::string &s) { 40 | s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(std::isspace)))); 41 | return s; 42 | } 43 | 44 | // trim from end 45 | static inline std::string &rtrim(std::string &s) { 46 | s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun(std::isspace))).base(), s.end()); 47 | return s; 48 | } 49 | 50 | // trim from both ends 51 | static inline std::string &trim(std::string &s) { 52 | return ltrim(rtrim(s)); 53 | } 54 | 55 | static Date parseDate(string dateStr) { 56 | 57 | Date date; 58 | date.day = -1; 59 | date.month = -1; 60 | date.year = -1; 61 | 62 | if (dateStr.size() == 11) { 63 | 64 | date.day = stoi(dateStr.substr(0,2).c_str()); 65 | date.year = stoi(dateStr.substr(7,4).c_str()); 66 | 67 | string strMonth = dateStr.substr(3, 3); 68 | if (strMonth.compare("JAN") == 0) 69 | date.month = 1; 70 | else if (strMonth.compare("FEB") == 0) 71 | date.month = 2; 72 | else if (strMonth.compare("MAR") == 0) 73 | date.month = 3; 74 | else if (strMonth.compare("APR") == 0) 75 | date.month = 4; 76 | else if (strMonth.compare("MAY") == 0) 77 | date.month = 5; 78 | else if (strMonth.compare("JUN") == 0) 79 | date.month = 6; 80 | else if (strMonth.compare("JUL") == 0) 81 | date.month = 7; 82 | else if (strMonth.compare("AUG") == 0) 83 | date.month = 8; 84 | else if (strMonth.compare("SEP") == 0) 85 | date.month = 9; 86 | else if (strMonth.compare("OCT") == 0) 87 | date.month = 10; 88 | else if (strMonth.compare("NOV") == 0) 89 | date.month = 11; 90 | else if (strMonth.compare("DEC") == 0) 91 | date.month = 12; 92 | } 93 | 94 | return date; 95 | } 96 | 97 | static int daysInMonth(int month, int year) { 98 | month--; //change from 1-12 to 0-11 99 | int numberOfDays; 100 | if (month == 4 || month == 6 || month == 9 || month == 11) { 101 | numberOfDays = 30; 102 | } else if (month == 2) { 103 | bool isLeapYear = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); 104 | if (isLeapYear) 105 | numberOfDays = 29; 106 | else 107 | numberOfDays = 28; 108 | } else { 109 | numberOfDays = 31; 110 | } 111 | return numberOfDays; 112 | } 113 | 114 | static Date addDays(Date date, int days) { 115 | //hopefull we are not adding many days... 116 | for (int i = 0; i != days; ++i) { 117 | date.day++; 118 | if (date.day > Helper::daysInMonth(date.month, date.year)) { 119 | date.day = 1; 120 | date.month++; 121 | if (date.month > 12) { 122 | date.month = 1; 123 | date.year++; 124 | } 125 | } 126 | } 127 | return date; 128 | } 129 | 130 | static string dateString(Date date) { 131 | string date_str; 132 | 133 | //construct the day 134 | if (date.day < 10) { 135 | date_str.append("0" + to_string(date.day)); 136 | } else { 137 | date_str.append(to_string(date.day)); 138 | } 139 | date_str.append("-"); 140 | 141 | //construct the month 142 | switch (date.month) { 143 | case 1: date_str.append("JAN"); break; 144 | case 2: date_str.append("FEB"); break; 145 | case 3: date_str.append("MAR"); break; 146 | case 4: date_str.append("APR"); break; 147 | case 5: date_str.append("MAY"); break; 148 | case 6: date_str.append("JUN"); break; 149 | case 7: date_str.append("JUL"); break; 150 | case 8: date_str.append("AUG"); break; 151 | case 9: date_str.append("SEP"); break; 152 | case 10: date_str.append("OCT"); break; 153 | case 11: date_str.append("NOV"); break; 154 | case 12: date_str.append("DEC"); break; 155 | } 156 | date_str.append("-"); 157 | 158 | //construct the year 159 | date_str.append(to_string(date.year)); 160 | 161 | return date_str; 162 | } 163 | 164 | static string formatPrice(double price) { 165 | stringstream ss; 166 | ss << setprecision(2) << std::fixed << "$" << price; 167 | return ss.str(); 168 | } 169 | static string formatDouble(double price) { 170 | stringstream ss; 171 | ss << setprecision(4) << std::fixed << "" << price; 172 | return ss.str(); 173 | } 174 | static string formatDoubleSmall(double price) { 175 | stringstream ss; 176 | ss << setprecision(2) << std::fixed << "" << price; 177 | return ss.str(); 178 | } 179 | }; 180 | } 181 | 182 | #endif 183 | 184 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/MyDateTableWidgetItem.h: -------------------------------------------------------------------------------- 1 | #include "QTableWidgetItem" 2 | #include "QDate" 3 | 4 | class MyDateTableWidgetItem : public QTableWidgetItem { 5 | public: 6 | MyDateTableWidgetItem(const QString txt = QString("0")) : QTableWidgetItem(txt) {} 7 | 8 | //For Date comparison 9 | bool operator <(const QTableWidgetItem &other) const 10 | { 11 | QDate date1 = QDate::fromString(text(), "dd-MMM-yyyy"); 12 | QDate date2 = QDate::fromString(other.text(), "dd-MMM-yyyy"); 13 | 14 | return date1 < date2; 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/MyTabWindow.h: -------------------------------------------------------------------------------- 1 | //myTabWidget.h File 2 | 3 | #ifndef MYTABWIDGET_H 4 | #define MYTABWIDGET_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include "ParseCSVData.h" 10 | #include "DisplayAnalysis.h" 11 | #include 12 | 13 | class MyTabWidget: public QTabWidget 14 | { 15 | Q_OBJECT 16 | public: 17 | MyTabWidget(QWidget* parent, std::ParseCSVData *pCSVdata) 18 | { 19 | this->setParent(parent); 20 | this->pCSVdata = pCSVdata; 21 | connect(this , SIGNAL(currentChanged(int)),this,SLOT(currentChangedSlot(int))); 22 | }; 23 | 24 | void addEqType(std::string &eqType) { eqTypeVec.push_back(eqType); } 25 | 26 | ~ MyTabWidget(){}; 27 | 28 | private: 29 | std::ParseCSVData *pCSVdata; 30 | std::vector eqTypeVec; 31 | std::set isCached; 32 | 33 | public slots: 34 | //Slot that is called when Tab selection changes 35 | void currentChangedSlot(int index) 36 | { 37 | //Don't process summary 38 | if (index == 0) { 39 | return; 40 | } 41 | 42 | //If the tab has not already been loaded then load it 43 | if (isCached.find(index) == isCached.end()) { 44 | DisplayAnalysis *dw = qobject_cast(this->widget(index)); 45 | dw->displayAnalysis(this->pCSVdata->getDataForEquityType(this->eqTypeVec[index])); 46 | isCached.insert(index); 47 | } 48 | }; 49 | 50 | }; 51 | #endif 52 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/MyTableWidgetItem.h: -------------------------------------------------------------------------------- 1 | #include "QTableWidgetItem" 2 | 3 | class MyTableWidgetItem : public QTableWidgetItem { 4 | public: 5 | MyTableWidgetItem(const QString txt = QString("0")) : QTableWidgetItem(txt) {} 6 | 7 | bool operator <(const QTableWidgetItem &other) const 8 | { 9 | QString str1 = text(); 10 | QString str2 = other.text(); 11 | 12 | if (str1[0] == '$') { 13 | str1.remove(0, 1); 14 | str2.remove(0, 1); // we assume both items have the same format 15 | } 16 | 17 | if (str1[str1.length() - 1] == '%') { 18 | str1.chop(1); 19 | str2.chop(1); // this works for "N%" and for "N %" formatted strings 20 | } 21 | 22 | return str1.toDouble() < str2.toDouble(); 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/ParamAnalysisHelper.cpp: -------------------------------------------------------------------------------- 1 | #include "ParamAnalysisHelper.h" 2 | 3 | namespace std 4 | { 5 | 6 | ParamAnalysisHelper::ParamAnalysisHelper() {} 7 | 8 | vector ParamAnalysisHelper::performParamAnalysis(vector equityTypes, 9 | vector> dateRanges, 10 | vector strategiesData) { 11 | 12 | vector paramSet = vector(); 13 | 14 | Para invalidPara; 15 | invalidPara.valid = false; 16 | 17 | //each equity type 18 | for (size_t equityIndex = 0; equityIndex < equityTypes.size(); ++equityIndex) { 19 | string equityType = equityTypes[equityIndex]; 20 | 21 | //each date range in each equity type 22 | for (size_t dateIndex = 0; dateIndex < dateRanges.size(); ++dateIndex) { 23 | string startDate = get<0>(dateRanges[dateIndex]); 24 | string endDate = get<1>(dateRanges[dateIndex]); 25 | 26 | ParamSet pSet = ParamSet(equityType, startDate, endDate, strategiesData.size()); 27 | 28 | vector returnVals = vector(); 29 | vector granalityVals = vector(); 30 | vector volatilityVals = vector(); 31 | vector analysisDataSetVals = vector(); 32 | 33 | //each strategy column 34 | for (StrategyData stratData : strategiesData) { 35 | 36 | if (stratData.dataForEachDateRange.size() <= dateIndex) { 37 | ERR_FATAL("ParamAnalysisHelper: data for date range too small!\n"); 38 | } 39 | 40 | ParseCSVData *data = stratData.dataForEachDateRange[dateIndex]; 41 | AnalysisData *dataSet = data->getDataForEquityType(equityType); 42 | 43 | if (dataSet == nullptr) { 44 | //no dataSet for this equity type, probably means there were no trades 45 | returnVals.push_back(invalidPara); 46 | granalityVals.push_back(invalidPara); 47 | volatilityVals.push_back(invalidPara); 48 | } else { 49 | 50 | Para paraReturns, granalityReturns, volatilityReturns; 51 | paraReturns.valid = false; 52 | granalityReturns.valid = false; 53 | volatilityReturns.valid = false; 54 | paraReturns.raw = 0.0; 55 | granalityReturns.raw = 0.0; 56 | volatilityReturns.raw = 0.0; 57 | 58 | double lastBuy = 0.0; 59 | signal lastSignal = SELL; 60 | double lastBuyTradeDayOffset; 61 | double sumDaysBetweenPairs = 0.0; 62 | int numPairs = 0; 63 | for (int tradeIndex = 0; tradeIndex < dataSet->tradeDataAvailable(); ++ tradeIndex) { 64 | TradeData tDat = dataSet->getData(tradeIndex); 65 | 66 | //returns calculated in pairs of buy then sell 67 | if (tDat.tradeSignal == BUY) { 68 | if (lastSignal == SELL) 69 | lastBuy = tDat.price; 70 | lastBuyTradeDayOffset = tDat.tradeDayOffset; 71 | } else { 72 | if (lastSignal == BUY) { 73 | if (lastBuy > 0.0) { 74 | double ret = (tDat.price - lastBuy) / lastBuy; 75 | 76 | volatilityReturns.raw += (ret >= 0.0) ? 1.0 : -1.0; 77 | volatilityReturns.valid = true; 78 | 79 | paraReturns.valid = true; 80 | paraReturns.raw += ret; //sum returns of buy/sell pairs 81 | 82 | numPairs++; 83 | sumDaysBetweenPairs += tDat.tradeDayOffset - lastBuyTradeDayOffset; 84 | } else { 85 | ERR("performParamAnalysis: lastBuy <= 0 error"); 86 | } 87 | } 88 | } 89 | 90 | lastSignal = tDat.tradeSignal; 91 | 92 | } 93 | 94 | if (numPairs > 0) { 95 | granalityReturns.valid = true; 96 | granalityReturns.raw = sumDaysBetweenPairs / (double)numPairs; 97 | } 98 | 99 | returnVals.push_back(paraReturns); 100 | granalityVals.push_back(granalityReturns); 101 | volatilityVals.push_back(volatilityReturns); 102 | analysisDataSetVals.push_back(dataSet); 103 | 104 | } 105 | 106 | } 107 | 108 | pSet.setParam(paraReturns, returnVals); 109 | pSet.setParam(paraGranality, granalityVals); 110 | pSet.setParam(paraVolatility, volatilityVals); 111 | pSet.setAnalysisDataForEachStrat(analysisDataSetVals); 112 | 113 | paramSet.push_back(pSet); 114 | } 115 | } 116 | 117 | return paramSet; 118 | } 119 | 120 | } 121 | 122 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/ParamAnalysisHelper.h: -------------------------------------------------------------------------------- 1 | #ifndef PARAMANALYSISHELPER_H 2 | #define PARAMANALYSISHELPER_H 3 | 4 | #include "GlobalIncludes.h" 5 | 6 | #include 7 | #include "ParamSet.h" 8 | #include "ParseCSVData.h" 9 | 10 | namespace std 11 | { 12 | 13 | struct StrategyData { 14 | string name; //name of strategy 15 | vector dataForEachDateRange; 16 | }; 17 | 18 | class ParamAnalysisHelper 19 | { 20 | private: 21 | ParamAnalysisHelper(); 22 | public: 23 | 24 | //equityTypes - list of each type of equity to expect and in the display order 25 | 26 | //dateRanges - (from, to) dates used for each strategy 27 | 28 | //strategiesData - data for each strategy run, strategiesData.dataForEachDateRange 29 | //should be the same for every strategy, since they need to be compared 30 | //"performParamAnalysis" DOES NOT become the owner of 31 | //each strategiesData.dataForEachDateRange object 32 | 33 | //the order of indexes in strategiesData will determine the index of the strategy in each 34 | //ParamSet 35 | 36 | static vector performParamAnalysis(vector equityTypes, 37 | vector> dateRanges, 38 | vector strategiesData); 39 | }; 40 | 41 | } 42 | 43 | #endif // PARAMANALYSISHELPER_H 44 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/ParamSet.cpp: -------------------------------------------------------------------------------- 1 | #include "ParamSet.h" 2 | 3 | namespace std 4 | { 5 | 6 | ParamSet::ParamSet(string equityType, string dateStart, 7 | string dateEnd, int numStrategies) : equityType(equityType), 8 | dateStart(dateStart), dateEnd(dateEnd), numStrategies(numStrategies) { 9 | 10 | if (numStrategies <= 0) { 11 | ERR_FATAL("ParamSet: numStrategies must be > 0!\n"); 12 | } 13 | 14 | } 15 | 16 | ParamSet::~ParamSet() {} 17 | 18 | void ParamSet::releaseAllAnalysisData() { 19 | for (AnalysisData *dat : analysisData) { 20 | if (dat != nullptr) delete dat; 21 | } 22 | analysisData = vector(); 23 | } 24 | 25 | //rawValsForEachStrat should be in same order, first strategy at index 0 and so on 26 | void ParamSet::setParam(QuantPara *paraType, vector rawValsForEachStrat) { 27 | string paraId = paraType->getName(); 28 | 29 | if (rawValsForEachStrat.size() != (size_t)numStrategies) { 30 | ERR_FATAL("ParamSet: Set param, numStrategies inconsistency error!\n"); 31 | } 32 | 33 | //find min max and average 34 | double sum = 0; 35 | bool firstYet = false; 36 | double max = 0; 37 | double min = 0; 38 | for (Para val : rawValsForEachStrat) { 39 | if (val.valid) { 40 | sum += val.raw; 41 | if (!firstYet) { 42 | firstYet = true; 43 | min = val.raw; 44 | max = val.raw; 45 | } else { 46 | if (val.raw > max) max = val.raw; 47 | if (val.raw < min) min = val.raw; 48 | } 49 | } 50 | } 51 | double avg = sum / double(rawValsForEachStrat.size()); 52 | 53 | vector quantParams = vector(); 54 | for (Para par : rawValsForEachStrat) { 55 | par.qnt = paraType->calculateParam(par.raw, max, min, avg); 56 | quantParams.push_back(par); 57 | } 58 | 59 | quantifiedParameters[paraId] = quantParams; 60 | } 61 | 62 | void ParamSet::setAnalysisDataForEachStrat(vector analysisData) { 63 | this->analysisData = analysisData; 64 | } 65 | 66 | 67 | AnalysisData *ParamSet::getAnalysisDataForStrat(int strategyIndex) { 68 | if (strategyIndex >= analysisData.size() || strategyIndex < 0) 69 | return nullptr; 70 | return analysisData[strategyIndex]; 71 | } 72 | 73 | Para ParamSet::getQuantifiedParameter(QuantPara *paraType, int strategyIndex) { 74 | string paraId = paraType->getName(); 75 | 76 | if (quantifiedParameters.find(paraId) == quantifiedParameters.end()) { 77 | ERR_FATAL("ParamSet: param type incorrect or not analyzed!\n"); 78 | } 79 | if (strategyIndex < 0 || strategyIndex >= numStrategies) { 80 | ERR_FATAL("ParamSet: requested strat index incorrect!\n"); 81 | } 82 | 83 | return quantifiedParameters[paraId][strategyIndex]; 84 | 85 | } 86 | 87 | } 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/ParamSet.h: -------------------------------------------------------------------------------- 1 | #ifndef PARAMSET_H 2 | #define PARAMSET_H 3 | 4 | #include "GlobalIncludes.h" 5 | 6 | #include 7 | #include "QuantPara.h" 8 | #include "AnalysisData.h" 9 | 10 | 11 | namespace std 12 | { 13 | 14 | struct Para { 15 | double qnt = 0.0; 16 | double raw = 0.0; 17 | bool valid = false; //false means there was not enough data to evaluate, or no trades etc 18 | 19 | inline Para operator+(Para a) { 20 | a.qnt += qnt; 21 | a.raw += raw; 22 | a.valid = a.valid && valid; 23 | return a; 24 | } 25 | }; 26 | 27 | class ParamSet 28 | { 29 | private: 30 | string equityType, dateStart, dateEnd; 31 | int numStrategies; 32 | map> quantifiedParameters; 33 | vector analysisData; 34 | public: 35 | ParamSet(string equityType, string dateStart, string dateEnd, int numStrategies); 36 | ~ParamSet(); 37 | 38 | //rawValsForEachStrat should be in same order, first strategy at index 0 and so on 39 | void setParam(QuantPara *paraType, vector rawValsForEachStrat); 40 | 41 | void setAnalysisDataForEachStrat(vector csvData); 42 | AnalysisData *getAnalysisDataForStrat(int strategyIndex); 43 | 44 | inline int getNumberOfStrategies() {return numStrategies;} 45 | inline string getEquityType() {return equityType;} 46 | inline string getStartDate() {return dateStart;} 47 | inline string getEndDate() {return dateEnd;} 48 | 49 | /* paraTypes: 50 | * paraReturns 51 | * paraGranality 52 | * paraVolatility 53 | * */ 54 | Para getQuantifiedParameter(QuantPara *paraType, int strategyIndex); 55 | 56 | //deletes all csv data this obj contains 57 | void releaseAllAnalysisData(); 58 | 59 | }; 60 | 61 | } 62 | 63 | #endif // PARAMSET_H 64 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/ParseCSVData.cpp: -------------------------------------------------------------------------------- 1 | #include "ParseCSVData.h" 2 | 3 | namespace std { 4 | 5 | ParseCSVData::ParseCSVData(string fileStr) { 6 | ifstream file(fileStr); 7 | 8 | if (file.is_open()) { 9 | 10 | int colSignal = -1; 11 | int colDate = -1; 12 | int colPrice = -1; 13 | int colVolume = -1; 14 | int colCompany = -1; 15 | 16 | string line; 17 | 18 | if (std::getline(file, line)) { 19 | 20 | vector columnTitles = parseCSVLine(line); 21 | 22 | //find the columns 23 | int index = 0; 24 | for (string strCol : columnTitles) { 25 | if (strCol.compare("#Company") == 0 || strCol.compare("Company Name") == 0) colCompany = index; 26 | else if (strCol.compare("Date") == 0 || strCol.compare("Date/Time") == 0) colDate = index; 27 | else if (strCol.compare("Price") == 0) colPrice = index; 28 | else if (strCol.compare("Volume") == 0) colVolume = index; 29 | else if (strCol.compare("Signal") == 0 || strCol.compare("Bid/ask") == 0) colSignal = index; 30 | index++; 31 | } 32 | 33 | if (colSignal != -1 && colDate != -1 34 | && colPrice != -1 && colVolume != -1 35 | && colCompany != -1) { 36 | 37 | while (std::getline(file, line)) { 38 | vector row = parseCSVLine(line); 39 | 40 | AnalysisData *data = nullptr; 41 | if (allData.find(row[colCompany]) == allData.end()) { 42 | allData[row[colCompany]] = new AnalysisData(row[colCompany]); 43 | equityTypes.push_back(row[colCompany]); 44 | } 45 | data = allData[row[colCompany]]; 46 | 47 | signal sig = BUY; 48 | if (row[colSignal].compare("S") == 0 || row[colSignal].compare("Sell") == 0) 49 | sig = SELL; 50 | 51 | data->addNextTradeData(sig, row[colDate], stod(row[colPrice]), stoi(row[colVolume])); 52 | } 53 | 54 | } 55 | } 56 | 57 | 58 | 59 | file.close(); 60 | } 61 | } 62 | 63 | ParseCSVData::~ParseCSVData() { 64 | for (auto data : allData) { 65 | delete data.second; 66 | } 67 | } 68 | 69 | 70 | vector ParseCSVData::getAllEquityTypes() { 71 | return equityTypes; 72 | } 73 | 74 | AnalysisData *ParseCSVData::getDataForEquityType(string equityType) { 75 | if (allData.find(equityType) == allData.end()) 76 | return nullptr; 77 | return allData[equityType]; 78 | } 79 | 80 | vector ParseCSVData::parseCSVLine(string line) { 81 | vector parsed; 82 | for(unsigned i = 0; i < line.length(); i++) { 83 | while(line[i] == ' ') ++i; 84 | unsigned b = i; 85 | for(; line[i] != __CSV_DELIM && i != line.length(); i++); 86 | string parsedComponent = line.substr(b, i - b); 87 | parsed.push_back(Helper::trim(parsedComponent)); 88 | } 89 | return parsed; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/ParseCSVData.h: -------------------------------------------------------------------------------- 1 | #ifndef PARSECSVDATA_H 2 | #define PARSECSVDATA_H 3 | 4 | #include "GlobalIncludes.h" 5 | 6 | #include "AnalysisData.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define __CSV_DELIM ',' 14 | 15 | namespace std { 16 | 17 | class ParseCSVData 18 | { 19 | private: 20 | vector equityTypes; 21 | map allData; 22 | 23 | vector parseCSVLine(string line); 24 | 25 | public: 26 | ParseCSVData(string fileStr); 27 | ~ParseCSVData(); 28 | 29 | vector getAllEquityTypes(); 30 | AnalysisData *getDataForEquityType(string equityType); 31 | }; 32 | 33 | 34 | } 35 | 36 | #endif // PARSECSVDATA_H 37 | 38 | 39 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/ParseInputCSVData.cpp: -------------------------------------------------------------------------------- 1 | #include "ParseInputCSVData.h" 2 | 3 | namespace std { 4 | 5 | ParseInputCSVData::ParseInputCSVData(string fileStr) { 6 | 7 | ifstream file(fileStr); 8 | 9 | if (file.is_open()) { 10 | int colCompany = -1; 11 | int colDate = -1; 12 | int colQualifier = -1; 13 | int colOpen = -1; 14 | int colHigh = -1; 15 | int colLow = -1; 16 | int colLast = -1; 17 | 18 | string line; 19 | 20 | if (std::getline(file, line)) { 21 | 22 | vector columnTitles = parseCSVLine(line); 23 | 24 | //find the columns 25 | int index = 0; 26 | 27 | for (string strCol : columnTitles) { 28 | if (strCol.compare("#RIC") == 0) colCompany = index; 29 | else if (strCol.compare("Date[L]") == 0) colDate = index; 30 | else if (strCol.compare("Qualifiers") == 0) colQualifier = index; 31 | else if (strCol.compare("Open") == 0) colOpen = index; 32 | else if (strCol.compare("High") == 0) colHigh = index; 33 | else if (strCol.compare("Low") == 0) colLow = index; 34 | else if (strCol.compare("Last") == 0) colLast = index; 35 | index++; 36 | } 37 | 38 | if (colCompany != -1 && colDate != -1 39 | && colQualifier != -1 && colOpen != -1 40 | && colHigh != -1 && colLow != -1 && colLast != -1) { 41 | 42 | //Loop through data rows 43 | while (std::getline(file, line)) { 44 | vector row = parseCSVLine(line); 45 | 46 | //Create tradedaydata struct for this row 47 | TradeDayData tdd; 48 | tdd.date = row[colDate]; 49 | 50 | if (row[colQualifier] == "No Trades") { 51 | //If no trades, simply ignore the data 52 | continue; 53 | } 54 | 55 | //If any of the value fields are empty, ignore row 56 | if (row[colHigh].empty() || row[colLast].empty() || row[colLow].empty() || row[colOpen].empty()) 57 | continue; 58 | 59 | tdd.high = std::stod(row[colHigh]); 60 | tdd.last = std::stod(row[colLast]); 61 | tdd.low = std::stod(row[colLow]); 62 | tdd.open = std::stod(row[colOpen]); 63 | 64 | 65 | //Check if map exists for this eqType 66 | if (data.find(row[colCompany]) != data.end()) { 67 | this->data.at(row[colCompany]).push_back(tdd); 68 | } 69 | //Else vector does not exist 70 | else { 71 | std::vector entry = std::vector(); 72 | entry.push_back(tdd); 73 | this->data[row[colCompany]] = entry; 74 | } 75 | } 76 | 77 | } 78 | } 79 | 80 | file.close(); 81 | } 82 | } 83 | 84 | vector ParseInputCSVData::parseCSVLine(string line) { 85 | vector parsed; 86 | for(unsigned i = 0; i < line.length(); i++) { 87 | while(line[i] == ' ') ++i; 88 | unsigned b = i; 89 | for(; line[i] != __CSV_DELIM && i != line.length(); i++); 90 | string parsedComponent = line.substr(b, i - b); 91 | parsed.push_back(Helper::trim(parsedComponent)); 92 | } 93 | return parsed; 94 | } 95 | 96 | 97 | } 98 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/ParseInputCSVData.h: -------------------------------------------------------------------------------- 1 | #ifndef PARSEINPUTCSVDATA_H 2 | #define PARSEINPUTCSVDATA_H 3 | 4 | #include "GlobalIncludes.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define __CSV_DELIM ',' 13 | 14 | struct TradeDayData { 15 | std::string date; 16 | double open; 17 | double high; 18 | double low; 19 | double last; 20 | }; 21 | 22 | namespace std { 23 | 24 | class ParseInputCSVData 25 | { 26 | private: 27 | 28 | public: 29 | ParseInputCSVData() {}; 30 | ParseInputCSVData(string fileStr); 31 | vector parseCSVLine(string line); 32 | 33 | //Map equity company to a vector of its trade days 34 | std::map> data; 35 | }; 36 | 37 | 38 | } 39 | 40 | #endif // PARSEINPUTCSVDATA_H 41 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/QuantPara.cpp: -------------------------------------------------------------------------------- 1 | #include "QuantPara.h" 2 | 3 | namespace std 4 | { 5 | 6 | QuantPara::QuantPara(string paramName) : paramName(paramName) { 7 | 8 | } 9 | 10 | QuantPara::~QuantPara() { 11 | 12 | } 13 | 14 | string QuantPara::getName() { 15 | return paramName; 16 | } 17 | 18 | double QuantPara::calculateParam(double rawVal, double max, double min, double avg) { 19 | if (rawVal > avg) { 20 | if (max == avg) 21 | return 1.0; 22 | return (rawVal - avg) / (max - avg); 23 | } 24 | if (min == avg) 25 | return -1.0; 26 | return -((avg - rawVal) / (avg - min)); 27 | } 28 | 29 | ParaReturns::ParaReturns() : QuantPara("Returns") {} 30 | double ParaReturns::calculateParam(double rawVal, double max, double min, double avg) { 31 | return QuantPara::calculateParam(rawVal, max, min, avg); 32 | } 33 | 34 | ParaGranality::ParaGranality() : QuantPara("Granularity") {} 35 | double ParaGranality::calculateParam(double rawVal, double max, double min, double avg) { 36 | return -QuantPara::calculateParam(rawVal, max, min, avg); 37 | } 38 | 39 | ParaVolatility::ParaVolatility() : QuantPara("Volatility") {} 40 | double ParaVolatility::calculateParam(double rawVal, double max, double min, double avg) { 41 | return QuantPara::calculateParam(rawVal, max, min, avg); 42 | } 43 | 44 | 45 | } 46 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/QuantPara.h: -------------------------------------------------------------------------------- 1 | #ifndef QUANTPARA_H 2 | #define QUANTPARA_H 3 | 4 | #include "GlobalIncludes.h" 5 | 6 | #include 7 | 8 | //use the static objects paraReturns, paraGranality and paraVolatility 9 | /* 10 | * Raw Values: 11 | * paraReturns - % made in returns 12 | * paraGranality - average days between each trade 13 | * paraVolatility - sum number of gains minus the sum number of times loss occured (using pairs) 14 | * */ 15 | 16 | namespace std 17 | { 18 | 19 | class QuantPara 20 | { 21 | private: 22 | string paramName; 23 | protected: 24 | QuantPara(string paramName); 25 | public: 26 | ~QuantPara(); 27 | string getName(); 28 | virtual double calculateParam(double rawVal, double max, double min, double avg); 29 | }; 30 | 31 | class ParaReturns : public QuantPara 32 | { 33 | public: 34 | ParaReturns(); 35 | virtual double calculateParam(double rawVal, double max, double min, double avg); 36 | }; 37 | 38 | class ParaGranality : public QuantPara 39 | { 40 | public: 41 | ParaGranality(); 42 | virtual double calculateParam(double rawVal, double max, double min, double avg); 43 | }; 44 | 45 | class ParaVolatility : public QuantPara 46 | { 47 | public: 48 | ParaVolatility(); 49 | virtual double calculateParam(double rawVal, double max, double min, double avg); 50 | }; 51 | 52 | static ParaReturns* paraReturns = new ParaReturns(); 53 | static ParaGranality* paraGranality = new ParaGranality(); 54 | static ParaVolatility* paraVolatility = new ParaVolatility(); 55 | 56 | } 57 | 58 | #endif // QUANTPARA_H 59 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/QuantitativeAnalysisDisplay.cpp: -------------------------------------------------------------------------------- 1 | #include "QuantitativeAnalysisDisplay.h" 2 | #include "ui_QuantitativeAnalysisDisplay.h" 3 | 4 | //#include 5 | 6 | QuantitativeAnalysisDisplay::QuantitativeAnalysisDisplay(QWidget *parent) : 7 | QWidget(parent), 8 | ui(new Ui::QuantitativeAnalysisDisplay) 9 | { 10 | ui->setupUi(this); 11 | 12 | setAnalysisCalled = false; 13 | 14 | connect(ui->comboBox,SIGNAL(currentIndexChanged(const int)), 15 | this,SLOT(handleSelectionChanged(const int))); 16 | } 17 | 18 | #define __WID 80.0 19 | #define __HEI 50.0 20 | #define __WID_TITLES_EQUITY 3 21 | #define __WID_TITLES_STRATS 4 22 | 23 | void QuantitativeAnalysisDisplay::drawTitle(QGridLayout *layout, std::string text, int row, int col, int width, int height) { 24 | QLabel *l = new QLabel(); 25 | l->setText(QString::fromStdString(text)); 26 | l->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); 27 | l->setStyleSheet("QLabel { background-color : white; color : black; }"); 28 | l->setFixedSize(__WID * width, __HEI * height); 29 | layout->addWidget(l, row, col, height, width); 30 | } 31 | 32 | #define RND_CCMP(i) (((int)(i))>255)?255:((((int)(i))setText(QString::fromStdString(std::Helper::formatDoubleSmall(para.qnt) + 41 | " \n(" + std::Helper::formatDoubleSmall(para.raw) + ")")); 42 | else 43 | l->setText(QString::fromStdString(std::Helper::formatDoubleSmall(para.qnt))); 44 | l->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); 45 | int red = 255; 46 | int green = 255; 47 | if (para.qnt < 0) { 48 | green = RND_CCMP(255 - (int)((-para.qnt)*DIFF_COL)); 49 | } else { 50 | red = RND_CCMP(255 - (int)((para.qnt)*DIFF_COL)); 51 | } 52 | 53 | 54 | l->setStyleSheet(QString::fromStdString("QLabel { background-color : rgba(" + std::to_string(red) + ", " 55 | + std::to_string(green) + ", 100, 255); color : black; }")); 56 | } else { 57 | l->setText(QString::fromStdString("")); 58 | l->setStyleSheet("QLabel { background-color : grey; color : black; }"); 59 | } 60 | l->setFixedSize(__WID * width, __HEI * height); 61 | layout->addWidget(l, row, col, height, width); 62 | } 63 | 64 | QuantitativeAnalysisDisplay::~QuantitativeAnalysisDisplay() 65 | { 66 | delete ui; 67 | for (std::ParamSet pSet : analysisData) pSet.releaseAllAnalysisData(); 68 | } 69 | 70 | 71 | void QuantitativeAnalysisDisplay::setAnalysis(std::vector analysisData, std::vector strategies) { 72 | if (setAnalysisCalled) { 73 | ERR_FATAL("QuantitativeAnalysisDisplay: setAnalysis called more then once!"); 74 | } 75 | setAnalysisCalled = true; 76 | this->analysisData = analysisData; 77 | this->strategies = strategies; 78 | this->currentDisplayOption = -1; 79 | this->buildAnalysis(this->analysisData, this->strategies, 0); 80 | this->buildAnalysis(this->analysisData, this->strategies, -1); 81 | } 82 | 83 | void QuantitativeAnalysisDisplay::buildAnalysis(std::vector analysisData, std::vector strategies, int displayOption) { 84 | //accesses the param for the first row, the second column (strategy), and the return param (out of the three types) 85 | 86 | while (ui->gridLayout->count() > 0) { 87 | ui->gridLayout->takeAt(0)->widget()->deleteLater(); 88 | } 89 | 90 | int strategyIndex = -1; 91 | for (std::string strategy : strategies) { 92 | strategyIndex++; 93 | this->drawTitle(ui->gridLayout, strategy, 0, __WID_TITLES_EQUITY + strategyIndex*__WID_TITLES_STRATS, __WID_TITLES_STRATS, 1); 94 | 95 | if (displayOption == -1) { 96 | this->drawTitle(ui->gridLayout, "Returns", 1, __WID_TITLES_EQUITY + 97 | strategyIndex*__WID_TITLES_STRATS + 0, 1, 1); 98 | this->drawTitle(ui->gridLayout, "Granularity", 1, __WID_TITLES_EQUITY + 99 | strategyIndex*__WID_TITLES_STRATS + 1, 1, 1); 100 | this->drawTitle(ui->gridLayout, "Volatility", 1, __WID_TITLES_EQUITY + 101 | strategyIndex*__WID_TITLES_STRATS + 2, 1, 1); 102 | } else if (displayOption == 0) { 103 | this->drawTitle(ui->gridLayout, "Returns", 1, __WID_TITLES_EQUITY + 104 | strategyIndex*__WID_TITLES_STRATS, 3, 1); 105 | } else if (displayOption == 1) { 106 | this->drawTitle(ui->gridLayout, "Granularity", 1, __WID_TITLES_EQUITY + 107 | strategyIndex*__WID_TITLES_STRATS, 3, 1); 108 | } else if (displayOption == 2) { 109 | this->drawTitle(ui->gridLayout, "Volatility", 1, __WID_TITLES_EQUITY + 110 | strategyIndex*__WID_TITLES_STRATS, 3, 1); 111 | } else if (displayOption == 3) { 112 | this->drawTitle(ui->gridLayout, "RGV Sum", 1, __WID_TITLES_EQUITY + 113 | strategyIndex*__WID_TITLES_STRATS, 3, 1); 114 | } 115 | 116 | } 117 | 118 | int startY = 2; 119 | 120 | this->drawTitle(ui->gridLayout, "", startY + (int)(analysisData.size()), 121 | 0, __WID_TITLES_EQUITY, 1); 122 | int sumRow = startY + (int)(analysisData.size()) + 1; 123 | this->drawTitle(ui->gridLayout, "Sum Total", sumRow, 124 | 0, __WID_TITLES_EQUITY, 1); 125 | 126 | std::Para zeroPara; 127 | zeroPara.valid = true; 128 | zeroPara.qnt = 0; 129 | zeroPara.raw = 0; 130 | 131 | vector> sums = vector>(); 132 | 133 | int rowIndex = -1; 134 | for (std::ParamSet paramSet : analysisData) { 135 | rowIndex++; 136 | this->drawTitle(ui->gridLayout, paramSet.getEquityType() + 137 | " \n(" + paramSet.getStartDate() + " to " 138 | + paramSet.getEndDate() + ")", startY + rowIndex, 139 | 0, __WID_TITLES_EQUITY, 1); 140 | 141 | for (int i = 0; i < paramSet.getNumberOfStrategies(); ++i) { 142 | std::Para r = paramSet.getQuantifiedParameter(std::paraReturns, i); 143 | std::Para g = paramSet.getQuantifiedParameter(std::paraGranality, i); 144 | std::Para v = paramSet.getQuantifiedParameter(std::paraVolatility, i); 145 | 146 | if (i >= sums.size()) { 147 | sums.push_back(make_tuple(zeroPara,zeroPara,zeroPara,zeroPara)); 148 | } 149 | 150 | get<0>(sums[i]) = get<0>(sums[i]) + r; 151 | get<1>(sums[i]) = get<1>(sums[i]) + g; 152 | get<2>(sums[i]) = get<2>(sums[i]) + v; 153 | get<3>(sums[i]) = get<3>(sums[i]) + r + g + v; 154 | 155 | if (displayOption == -1) { 156 | this->drawQuantValue(ui->gridLayout, r, rowIndex + startY, 157 | __WID_TITLES_EQUITY + i*__WID_TITLES_STRATS + 0, 1, 1, true); 158 | this->drawQuantValue(ui->gridLayout, g, rowIndex + startY, 159 | __WID_TITLES_EQUITY + i*__WID_TITLES_STRATS + 1, 1, 1, true); 160 | this->drawQuantValue(ui->gridLayout, v, rowIndex + startY, 161 | __WID_TITLES_EQUITY + i*__WID_TITLES_STRATS + 2, 1, 1, true); 162 | } else if (displayOption == 0) { 163 | this->drawQuantValue(ui->gridLayout, r, rowIndex + startY, 164 | __WID_TITLES_EQUITY + i*__WID_TITLES_STRATS + 0, 3, 1, true); 165 | } else if (displayOption == 1) { 166 | this->drawQuantValue(ui->gridLayout, g, rowIndex + startY, 167 | __WID_TITLES_EQUITY + i*__WID_TITLES_STRATS + 0, 3, 1, true); 168 | } else if (displayOption == 2) { 169 | this->drawQuantValue(ui->gridLayout, v, rowIndex + startY, 170 | __WID_TITLES_EQUITY + i*__WID_TITLES_STRATS + 0, 3, 1, true); 171 | } else if (displayOption == 3) { 172 | this->drawQuantValue(ui->gridLayout, v + g + r, rowIndex + startY, 173 | __WID_TITLES_EQUITY + i*__WID_TITLES_STRATS + 0, 3, 1, false); 174 | } 175 | 176 | //add button of elaboration and analysis, using the CamelPushButton :) 177 | CamelPushButton *button = new CamelPushButton(); 178 | button->setText("Elab."); 179 | button->hump = paramSet.getAnalysisDataForStrat(i); 180 | QObject::connect(button, SIGNAL(clicked()),this, SLOT(clickedSlot())); 181 | ui->gridLayout->addWidget(button, rowIndex + startY, __WID_TITLES_EQUITY + i*__WID_TITLES_STRATS + 3, 1, 1); 182 | } 183 | } 184 | 185 | int index = -1; 186 | for (tuple summm : sums) { 187 | index++; 188 | if (displayOption == -1) { 189 | this->drawQuantValue(ui->gridLayout, get<0>(summm), sumRow, 190 | __WID_TITLES_EQUITY + index*__WID_TITLES_STRATS + 0, 1, 1, true); 191 | this->drawQuantValue(ui->gridLayout, get<1>(summm), sumRow, 192 | __WID_TITLES_EQUITY + index*__WID_TITLES_STRATS + 1, 1, 1, true); 193 | this->drawQuantValue(ui->gridLayout, get<2>(summm), sumRow, 194 | __WID_TITLES_EQUITY + index*__WID_TITLES_STRATS + 2, 1, 1, true); 195 | } else if (displayOption == 0) { 196 | this->drawQuantValue(ui->gridLayout, get<0>(summm), sumRow, 197 | __WID_TITLES_EQUITY + index*__WID_TITLES_STRATS + 0, 3, 1, true); 198 | } else if (displayOption == 1) { 199 | this->drawQuantValue(ui->gridLayout, get<1>(summm), sumRow, 200 | __WID_TITLES_EQUITY + index*__WID_TITLES_STRATS + 0, 3, 1, true); 201 | } else if (displayOption == 2) { 202 | this->drawQuantValue(ui->gridLayout, get<2>(summm), sumRow, 203 | __WID_TITLES_EQUITY + index*__WID_TITLES_STRATS + 0, 3, 1, true); 204 | } else if (displayOption == 3) { 205 | this->drawQuantValue(ui->gridLayout, get<3>(summm), sumRow, 206 | __WID_TITLES_EQUITY + index*__WID_TITLES_STRATS + 0, 3, 1, false); 207 | } 208 | } 209 | 210 | } 211 | 212 | 213 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/QuantitativeAnalysisDisplay.h: -------------------------------------------------------------------------------- 1 | #ifndef QUANTITATIVEANALYSISDISPLAY_H 2 | #define QUANTITATIVEANALYSISDISPLAY_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | //#include 9 | 10 | #include 11 | 12 | #include "ParamSet.h" 13 | #include "CamelPushButton.h" 14 | #include "DisplayAnalysis.h" 15 | 16 | namespace Ui { 17 | class QuantitativeAnalysisDisplay; 18 | } 19 | 20 | class QuantitativeAnalysisDisplay : public QWidget 21 | { 22 | Q_OBJECT 23 | 24 | public: 25 | explicit QuantitativeAnalysisDisplay(QWidget *parent = 0); 26 | ~QuantitativeAnalysisDisplay(); 27 | 28 | void setAnalysis(std::vector analysisData, std::vector strategies); 29 | 30 | public slots: 31 | void handleSelectionChanged(int index) 32 | { 33 | this->buildAnalysis(this->analysisData, this->strategies, index - 1); 34 | }; 35 | void clickedSlot() 36 | { 37 | std::AnalysisData *data = static_cast(((CamelPushButton*)sender())->hump); 38 | if (data != nullptr) { 39 | DisplayAnalysis *disp = new DisplayAnalysis(); 40 | disp->show(); 41 | disp->displayAnalysis(data); 42 | } 43 | }; 44 | 45 | private: 46 | Ui::QuantitativeAnalysisDisplay *ui; 47 | 48 | bool setAnalysisCalled; 49 | 50 | void drawTitle(QGridLayout *layout, std::string text, int row, int col, int width, int height); 51 | void drawQuantValue(QGridLayout *layout, std::Para para, int row, int col, int width, int height, bool showRaw); 52 | 53 | //displayOption = -1 normal, 0 = returns, 1 = granularity, 2 = volatility 54 | std::vector analysisData; 55 | std::vector strategies; 56 | int currentDisplayOption; 57 | void buildAnalysis(std::vector analysisData, std::vector strategies, int displayOption); 58 | 59 | }; 60 | 61 | #endif // QUANTITATIVEANALYSISDISPLAY_H 62 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/QuantitativeAnalysisDisplay.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | QuantitativeAnalysisDisplay 4 | 5 | 6 | 7 | 0 8 | 0 9 | 640 10 | 640 11 | 12 | 13 | 14 | Quantitative Analysis 15 | 16 | 17 | 18 | 19 | 20 | true 21 | 22 | 23 | 24 | 25 | 0 26 | 0 27 | 614 28 | 542 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 0 46 | 60 47 | 48 | 49 | 50 | 51 | 52 | 10 53 | 10 54 | 151 55 | 31 56 | 57 | 58 | 59 | Display Options: 60 | 61 | 62 | 63 | 64 | 65 | 130 66 | 10 67 | 174 68 | 26 69 | 70 | 71 | 72 | 73 | Display All 74 | 75 | 76 | 77 | 78 | Returns 79 | 80 | 81 | 82 | 83 | Granality 84 | 85 | 86 | 87 | 88 | Volatility 89 | 90 | 91 | 92 | 93 | Display Sum 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/ReturnsAnalysis.cpp: -------------------------------------------------------------------------------- 1 | #include "ReturnsAnalysis.h" 2 | 3 | void ReturnsAnalysis::returnsAnalysis(std::AnalysisData *data) { 4 | 5 | //maintain queues of trades, one for buy and one for sell 6 | // int is for maintaining which one came first 7 | vector> buy_trades; 8 | vector> sell_trades; 9 | 10 | //maintain total return percentage 11 | double net_return_perc = 0; 12 | 13 | //read the trade orders line by line 14 | for (int i = 0; i < data->tradeDataAvailable(); i++) { 15 | 16 | //load the vectors as appropriate 17 | if (data->getData(i).tradeSignal == BUY) { 18 | buy_trades.push_back(tuple(data->getData(i),i)); 19 | } else { 20 | sell_trades.push_back(tuple(data->getData(i),i)); 21 | } 22 | 23 | //Determine whether there is a buy-sell / sell-buy pair 24 | if (buy_trades.size() > 0 && sell_trades.size() > 0) { 25 | tuple buy_trade = buy_trades.front(); 26 | tuple sell_trade = sell_trades.front(); 27 | 28 | if (get<1>(sell_trade) > get<1>(buy_trade)) { 29 | //a buy-sell pair 30 | printf("Buy@%lf,", get<0>(buy_trade).price); 31 | printf("Sell@%lf. ", get<0>(sell_trade).price); 32 | printf("Date: %s. ",get<0>(sell_trade).date.c_str()); 33 | } else { 34 | //a sell-buy pair 35 | printf("Buy@%lf,", get<0>(sell_trade).price); 36 | printf("Sell@%lf. ", get<0>(buy_trade).price); 37 | printf("Date: %s. ",get<0>(buy_trade).date.c_str()); 38 | } 39 | 40 | //Calculate return 41 | double return_perc = (get<0>(sell_trade).price - get<0>(buy_trade).price) / get<0>(buy_trade).price; 42 | printf("Return: %lf",return_perc); 43 | 44 | //update total return 45 | net_return_perc += return_perc; 46 | 47 | //Remove the first trades from both queues 48 | buy_trades.erase(buy_trades.begin(),buy_trades.begin()+1); 49 | sell_trades.erase(sell_trades.begin(),sell_trades.begin()+1); 50 | } 51 | 52 | 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/ReturnsAnalysis.h: -------------------------------------------------------------------------------- 1 | #ifndef RETURNSANALYSIS_H 2 | #define RETURNSANALYSIS_H 3 | 4 | #include 5 | #include "AnalysisDisplays.h" 6 | #include "AnalysisData.h" 7 | 8 | //For reading in the csv file 9 | #include 10 | #include 11 | #include 12 | 13 | #define PRICE 2 14 | #define DATE 1 15 | #define BUY_SELL_SIGNAL 5 16 | 17 | using namespace std; 18 | 19 | namespace Ui { 20 | class ReturnsAnalysis; 21 | } 22 | 23 | class ReturnsAnalysis : public QMainWindow 24 | { 25 | Q_OBJECT 26 | 27 | public: 28 | explicit ReturnsAnalysis(QWidget *parent = 0); 29 | ~ReturnsAnalysis(); 30 | 31 | private slots: 32 | void on_readFile_clicked(void); //read in a particular csv file 33 | void returnsAnalysis(std::AnalysisData *data); 34 | 35 | private: 36 | Ui::ReturnsAnalysis *ui; 37 | }; 38 | 39 | #endif // RETURNSANALYSIS_H 40 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/SummaryForm.cpp: -------------------------------------------------------------------------------- 1 | #include "SummaryForm.h" 2 | #include "ui_summaryform.h" 3 | #include "MyTableWidgetItem.h" 4 | 5 | SummaryForm::SummaryForm(QWidget *parent) : 6 | QWidget(parent), ui(new Ui::SummaryForm) 7 | { 8 | this->ui->setupUi(this); 9 | } 10 | 11 | void SummaryForm::setTotalNetReturns(ParseCSVData * pCSVdata, vector eqTypes) { 12 | double runningNetValue = 0; 13 | double runningNetPerc = 0; 14 | 15 | double mostProfitableReturns = 0; 16 | double leastProfitableReturns = 0; 17 | double mostProfitableReturnsPerc = -1000000; 18 | double leastProfitableReturnsPerc = 1000000; 19 | string mostProfitableCompany; 20 | string leastProfitableCompany; 21 | 22 | //Loop through provided list of companies 23 | for (auto eqType = eqTypes.begin(); eqType != eqTypes.end(); ++eqType) { 24 | AnalysisData *ad = pCSVdata->getDataForEquityType(*eqType); 25 | 26 | //maintain queues of trades, one for buy and one for sell 27 | // int is for maintaining which one came first 28 | vector> buy_trades; 29 | vector> sell_trades; 30 | 31 | //maintain total return percentage 32 | double net_return_value = 0; 33 | double net_return_perc = 0; 34 | 35 | //read the trade orders line by line 36 | for (int i = 0; i < ad->tradeDataAvailable(); i++) { 37 | 38 | //load the vectors as appropriate 39 | if (ad->getData(i).tradeSignal == BUY) { 40 | buy_trades.push_back(tuple(ad->getData(i),i)); 41 | } else { 42 | sell_trades.push_back(tuple(ad->getData(i),i)); 43 | } 44 | 45 | //Determine whether there is a buy-sell / sell-buy pair 46 | if (buy_trades.size() > 0 && sell_trades.size() > 0) { 47 | tuple buy_trade = buy_trades.front(); 48 | tuple sell_trade = sell_trades.front(); 49 | 50 | //Calculate and construct return value string 51 | double return_value =(get<0>(sell_trade).price - get<0>(buy_trade).price); 52 | 53 | 54 | //Calculate and construct return percentage string 55 | double return_perc = (get<0>(sell_trade).price - get<0>(buy_trade).price) * 100 / get<0>(buy_trade).price; 56 | 57 | //update total return value and percentage 58 | net_return_value += return_value; 59 | net_return_perc += return_perc; 60 | 61 | //Remove the first trades from both queues 62 | buy_trades.erase(buy_trades.begin(),buy_trades.begin()+1); 63 | sell_trades.erase(sell_trades.begin(),sell_trades.begin()+1); 64 | } 65 | } 66 | 67 | //Update running net returns 68 | runningNetValue += net_return_value; 69 | runningNetPerc += net_return_perc; 70 | 71 | //Check profitibility 72 | if (net_return_perc > mostProfitableReturnsPerc) { 73 | mostProfitableReturns = net_return_value; 74 | mostProfitableReturnsPerc = net_return_perc; 75 | mostProfitableCompany = *eqType; 76 | } 77 | 78 | if (net_return_perc < leastProfitableReturnsPerc) { 79 | leastProfitableReturns = net_return_value; 80 | leastProfitableReturnsPerc = net_return_perc; 81 | leastProfitableCompany = *eqType; 82 | } 83 | 84 | //Add Returns for this company to table 85 | 86 | //increase table rows by 1 87 | int currRows = ui->summary_returnsTable->rowCount(); 88 | ui->summary_returnsTable->setRowCount(currRows + 1); 89 | 90 | 91 | QTableWidgetItem* col0 = new QTableWidgetItem(QString::fromStdString(*eqType), QTableWidgetItem::Type); 92 | col0->setFlags(col0->flags() ^ Qt::ItemIsEditable); 93 | col0->setTextAlignment(Qt::AlignHCenter); 94 | ui->summary_returnsTable->setItem(currRows, 0, col0); 95 | 96 | //Use custom int type for this column 97 | MyTableWidgetItem* col1 = new MyTableWidgetItem(QString::number(net_return_perc)); 98 | col1->setFlags(col1->flags() ^ Qt::ItemIsEditable); 99 | col1->setTextAlignment(Qt::AlignHCenter); 100 | ui->summary_returnsTable->setItem(currRows, 1, col1); 101 | } 102 | 103 | //Display cummalative net returns 104 | QString net_return_perc_str; 105 | 106 | if (runningNetPerc < 0) { 107 | ui->summary_totalnetreturns->setStyleSheet("color:red;font: 14pt \"Verdana\";"); 108 | } else { 109 | ui->summary_totalnetreturns->setStyleSheet("color:green;font: 14pt \"Verdana\";"); 110 | } 111 | 112 | net_return_perc_str.append(QString::number(runningNetPerc)); 113 | net_return_perc_str.append("%"); 114 | ui->summary_totalnetreturns->setText(net_return_perc_str); 115 | 116 | //Display most/least profitable companies 117 | 118 | //Most profitable 119 | QString mp_net_return_perc_str; 120 | 121 | if (mostProfitableReturnsPerc < 0) { 122 | ui->summary_mostprofitableequity->setStyleSheet("color:red;font: 14pt \"MS Shell Dlg 2\";"); 123 | } else { 124 | ui->summary_mostprofitableequity->setStyleSheet("color:green;font: 14pt \"MS Shell Dlg 2\";"); 125 | } 126 | 127 | mp_net_return_perc_str.append(mostProfitableCompany.c_str()); 128 | mp_net_return_perc_str.append(" (" + QString::number(mostProfitableReturnsPerc) + "%)"); 129 | ui->summary_mostprofitableequity->setText(mp_net_return_perc_str); 130 | 131 | //Least Profitable 132 | QString lp_net_return_perc_str; 133 | 134 | if (leastProfitableReturnsPerc < 0) { 135 | ui->summary_leastprofitableequity->setStyleSheet("color:red;font: 14pt \"MS Shell Dlg 2\";"); 136 | } else { 137 | ui->summary_leastprofitableequity->setStyleSheet("color:green;font: 14pt \"MS Shell Dlg 2\";"); 138 | } 139 | 140 | lp_net_return_perc_str.append(leastProfitableCompany.c_str()); 141 | lp_net_return_perc_str.append(" (" + QString::number(leastProfitableReturnsPerc) + "%)"); 142 | ui->summary_leastprofitableequity->setText(lp_net_return_perc_str); 143 | } 144 | 145 | 146 | vector> SummaryForm::export_Summary(ParseCSVData * pCSVdata, vector eqTypes) { 147 | double runningNetValue = 0; 148 | double runningNetPerc = 0; 149 | 150 | vector> summaryData; 151 | 152 | //Loop through provided list of companies 153 | for (auto eqType = eqTypes.begin(); eqType != eqTypes.end(); ++eqType) { 154 | AnalysisData *ad = pCSVdata->getDataForEquityType(*eqType); 155 | 156 | //maintain queues of trades, one for buy and one for sell 157 | // int is for maintaining which one came first 158 | vector> buy_trades; 159 | vector> sell_trades; 160 | 161 | //maintain total return percentage 162 | double net_return_value = 0; 163 | double net_return_perc = 0; 164 | 165 | //read the trade orders line by line 166 | for (int i = 0; i < ad->tradeDataAvailable(); i++) { 167 | 168 | //load the vectors as appropriate 169 | if (ad->getData(i).tradeSignal == BUY) { 170 | buy_trades.push_back(tuple(ad->getData(i),i)); 171 | } else { 172 | sell_trades.push_back(tuple(ad->getData(i),i)); 173 | } 174 | 175 | //Determine whether there is a buy-sell / sell-buy pair 176 | if (buy_trades.size() > 0 && sell_trades.size() > 0) { 177 | tuple buy_trade = buy_trades.front(); 178 | tuple sell_trade = sell_trades.front(); 179 | 180 | //Calculate and construct return value string 181 | double return_value =(get<0>(sell_trade).price - get<0>(buy_trade).price); 182 | 183 | 184 | //Calculate and construct return percentage string 185 | double return_perc = (get<0>(sell_trade).price - get<0>(buy_trade).price) * 100 / get<0>(buy_trade).price; 186 | 187 | //update total return value and percentage 188 | net_return_value += return_value; 189 | net_return_perc += return_perc; 190 | 191 | //Remove the first trades from both queues 192 | buy_trades.erase(buy_trades.begin(),buy_trades.begin()+1); 193 | sell_trades.erase(sell_trades.begin(),sell_trades.begin()+1); 194 | } 195 | } 196 | 197 | //Update running net returns 198 | runningNetValue += net_return_value; 199 | runningNetPerc += net_return_perc; 200 | 201 | // *eqType (company name) 202 | // net_return_prec (return returns %) 203 | 204 | tuple temp = make_tuple(*eqType, net_return_perc); 205 | summaryData.push_back(temp); 206 | } 207 | tuple totals = make_tuple("Total", runningNetPerc); 208 | summaryData.push_back(totals); 209 | 210 | return summaryData; 211 | 212 | } 213 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/SummaryForm.h: -------------------------------------------------------------------------------- 1 | #ifndef SUMMARYFORM_H 2 | #define SUMMARYFORM_H 3 | 4 | #include "GlobalIncludes.h" 5 | 6 | #include "ParseCSVData.h" 7 | #include "AnalysisData.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; //for vectors 14 | 15 | namespace Ui { 16 | class SummaryForm; 17 | } 18 | 19 | class SummaryForm : public QWidget 20 | { 21 | Q_OBJECT 22 | 23 | public: 24 | explicit SummaryForm(QWidget *parent = 0); 25 | void setTotalNetReturns(ParseCSVData * pCSVdata, vector eqTypes); 26 | static vector> export_Summary(ParseCSVData * pCSVdata, vector eqTypes); 27 | 28 | private: 29 | Ui::SummaryForm *ui; 30 | }; 31 | 32 | #endif // SUMMARYFORM_H 33 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/TradeSimulator.h: -------------------------------------------------------------------------------- 1 | #ifndef TRADESIMULATOR_H 2 | #define TRADESIMULATOR_H 3 | 4 | #include "GlobalIncludes.h" 5 | #include "ParseInputCSVData.h" 6 | #include "ui_tradesimulator.h" 7 | #include "AnalysisData.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | using namespace std; //for vectors 19 | 20 | namespace Ui { 21 | class TradeSimulator; 22 | } 23 | 24 | class TradeSimulator : public QWidget 25 | { 26 | Q_OBJECT 27 | 28 | public: 29 | explicit TradeSimulator(QWidget *parent = 0); 30 | void addTradeData(string eqType, vector data); 31 | 32 | //Runs trade simulation in a thread 33 | void runSimulation(); 34 | void simulationWorker(); 35 | 36 | void displayGraphAnalysis(std::AnalysisData *data); 37 | void displayReturnsAnalysis(std::AnalysisData *data); 38 | 39 | void insertRowIntoReturnsAnalysis(std::string buySellPair, 40 | std::string date, 41 | std::string returnValue, 42 | std::string returnPerc); 43 | 44 | signals: 45 | void sendEndThread(); 46 | 47 | private slots: 48 | void on_sendBuySignal_clicked(); 49 | void on_sendSellSignal_clicked(); 50 | void on_exportOrderFileButton_clicked(); 51 | 52 | void doThreadEndActions(); 53 | 54 | private: 55 | Ui::TradeSimulator *ui; 56 | std::string eqType; 57 | vector data; 58 | vector userTrades; 59 | QGraphicsScene *scene = nullptr; 60 | std::thread *simWorker = nullptr; 61 | std::AnalysisData *cumulativeData = nullptr; 62 | bool isBuyEnabled = true; 63 | bool isSellEnabled = false; 64 | int index = -1; 65 | int lastTradeIndex = -1; 66 | static const int updatePeriod = 3000; 67 | }; 68 | 69 | #endif // TRADESIMULATOR_H 70 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobeigi/Algorithmic-Trading/b097c04ad73bf725be22f3ad76395de8ddac9349/Trading_Platform_GUI/icon.ico -------------------------------------------------------------------------------- /Trading_Platform_GUI/iconise.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "icon.ico" -------------------------------------------------------------------------------- /Trading_Platform_GUI/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | MainWindow w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include "GlobalIncludes.h" 5 | #include "TradeSimulator.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include //for processing directories 12 | 13 | #ifdef _WIN32 //windows 32 and 64bit 14 | #include 15 | #endif 16 | 17 | #include "AnalysisDisplays.h" 18 | #include "ParamAnalysisHelper.h" 19 | #include "QuantitativeAnalysisDisplay.h" 20 | #include "SummaryForm.h" 21 | #include "ParseInputCSVData.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include //for creating a params file 27 | #include //for params error checking 28 | 29 | //For checking params 30 | #define OK 0 //ok status 31 | #define INPUTCSV_EQ_OUTPUTCSV 1 32 | #define ENDDATE_BEFORE_STARTDATE 2 33 | #define NO_INPUTCSV_SELECTED 3 34 | #define NO_OUTPUTCSV_SELECTED 4 35 | 36 | using namespace std; 37 | 38 | namespace Ui { 39 | class MainWindow; 40 | } 41 | 42 | class MainWindow : public QMainWindow 43 | { 44 | Q_OBJECT 45 | 46 | public: 47 | explicit MainWindow(QWidget *parent = 0); 48 | ~MainWindow(); 49 | 50 | 51 | private slots: 52 | 53 | //for analysing a module 54 | void on_browseModule_clicked(); 55 | void on_browseCSV_clicked(); 56 | int on_execute_button_clicked(); 57 | vector check_params(void); 58 | 59 | //for analysing an output csv 60 | void on_browse_outputcsv_clicked(); 61 | int loadordercsvfile(); 62 | int on_showanalysis_button_clicked(); 63 | 64 | int on_selectall_clicked(); 65 | int on_deselectall_clicked(); 66 | int on_inverseSelection_clicked(); 67 | 68 | int check_outputcsv(void); 69 | 70 | //quantative analysis 71 | //returns param set and list of strategies (name, threshold, returns) 72 | tuple, vector>> doExecuteAnalysis(bool formatForCSV); 73 | void on_analysisInputCSVButton_clicked(); 74 | void on_analysisBrowseStrategyButton_clicked(); 75 | void on_clearStrategyButton_clicked(); 76 | void on_analysisClearDateButton_clicked(); 77 | void on_addStrategyButton_clicked(); 78 | void on_analysisAddDateButton_clicked(); 79 | void on_analysisExecuteButton_clicked(); 80 | void on_saveCSVExecuteButton_clicked(); 81 | void on_exportsummary_clicked(); 82 | void on_tradeSimulator_browseCSV_clicked(); 83 | void on_tradeSimulatorRunSimulationButton_clicked(); 84 | 85 | 86 | private: 87 | Ui::MainWindow *ui; 88 | AnalysisDisplays *ad = nullptr; 89 | ParseInputCSVData inputCSV; 90 | TradeSimulator *ts = nullptr; 91 | string construct_date_string(int day, int month, int year); 92 | QString getRandomString() const; 93 | QString getYear(QString yr); 94 | }; 95 | 96 | #endif // MAINWINDOW_H 97 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/qt.config: -------------------------------------------------------------------------------- 1 | [Paths] 2 | Prefix=../ 3 | Libraries=/ 4 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/resources.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | resources/file_csv.png 4 | resources/displayanalysis.png 5 | resources/logo.png 6 | resources/terminal.gif 7 | resources/run.png 8 | resources/run_program.gif 9 | resources/barchart.png 10 | resources/analyse.jpg 11 | resources/export_csv.png 12 | resources/globe.gif 13 | resources/letterB.png 14 | resources/letterS.png 15 | 16 | 17 | -------------------------------------------------------------------------------- /Trading_Platform_GUI/resources/analyse.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobeigi/Algorithmic-Trading/b097c04ad73bf725be22f3ad76395de8ddac9349/Trading_Platform_GUI/resources/analyse.jpg -------------------------------------------------------------------------------- /Trading_Platform_GUI/resources/barchart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobeigi/Algorithmic-Trading/b097c04ad73bf725be22f3ad76395de8ddac9349/Trading_Platform_GUI/resources/barchart.png -------------------------------------------------------------------------------- /Trading_Platform_GUI/resources/displayanalysis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobeigi/Algorithmic-Trading/b097c04ad73bf725be22f3ad76395de8ddac9349/Trading_Platform_GUI/resources/displayanalysis.png -------------------------------------------------------------------------------- /Trading_Platform_GUI/resources/export_csv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobeigi/Algorithmic-Trading/b097c04ad73bf725be22f3ad76395de8ddac9349/Trading_Platform_GUI/resources/export_csv.png -------------------------------------------------------------------------------- /Trading_Platform_GUI/resources/file_csv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobeigi/Algorithmic-Trading/b097c04ad73bf725be22f3ad76395de8ddac9349/Trading_Platform_GUI/resources/file_csv.png -------------------------------------------------------------------------------- /Trading_Platform_GUI/resources/globe.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobeigi/Algorithmic-Trading/b097c04ad73bf725be22f3ad76395de8ddac9349/Trading_Platform_GUI/resources/globe.gif -------------------------------------------------------------------------------- /Trading_Platform_GUI/resources/letterB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobeigi/Algorithmic-Trading/b097c04ad73bf725be22f3ad76395de8ddac9349/Trading_Platform_GUI/resources/letterB.png -------------------------------------------------------------------------------- /Trading_Platform_GUI/resources/letterS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobeigi/Algorithmic-Trading/b097c04ad73bf725be22f3ad76395de8ddac9349/Trading_Platform_GUI/resources/letterS.png -------------------------------------------------------------------------------- /Trading_Platform_GUI/resources/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobeigi/Algorithmic-Trading/b097c04ad73bf725be22f3ad76395de8ddac9349/Trading_Platform_GUI/resources/logo.png -------------------------------------------------------------------------------- /Trading_Platform_GUI/resources/run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobeigi/Algorithmic-Trading/b097c04ad73bf725be22f3ad76395de8ddac9349/Trading_Platform_GUI/resources/run.png -------------------------------------------------------------------------------- /Trading_Platform_GUI/resources/run_program.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobeigi/Algorithmic-Trading/b097c04ad73bf725be22f3ad76395de8ddac9349/Trading_Platform_GUI/resources/run_program.gif -------------------------------------------------------------------------------- /Trading_Platform_GUI/resources/terminal.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mobeigi/Algorithmic-Trading/b097c04ad73bf725be22f3ad76395de8ddac9349/Trading_Platform_GUI/resources/terminal.gif -------------------------------------------------------------------------------- /Trading_Platform_GUI/summaryform.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | SummaryForm 4 | 5 | 6 | 7 | 0 8 | 0 9 | 750 10 | 652 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | font: 14pt "Verdana"; 25 | 26 | 27 | Total Net Returns: 28 | 29 | 30 | 31 | 32 | 33 | 34 | font: 14pt "MS Shell Dlg 2";color:red; 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | font: 14pt "Verdana"; 49 | 50 | 51 | Most Profitable Equity: 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | font: 14pt "Verdana"; 73 | 74 | 75 | Least Profitable Equity: 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | true 99 | 100 | 101 | true 102 | 103 | 104 | 330 105 | 106 | 107 | 30 108 | 109 | 110 | 30 111 | 112 | 113 | 114 | Equity 115 | 116 | 117 | 118 | 119 | Net Returns (%) 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /src/CSVReader.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // CSVReader.cpp 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | #include "CSVReader.h" 10 | 11 | namespace std 12 | { 13 | 14 | CSVReader::CSVReader(string dataFile, bool * foundFile) { 15 | 16 | file = new ifstream(dataFile, ios::in); 17 | * foundFile = false; 18 | hasNextLine = false; 19 | 20 | if (file->is_open() && getline(*file, currentLine)) { 21 | * foundFile = true; 22 | hasNextLine = true; 23 | } else { 24 | if (file->is_open()) 25 | file->close(); 26 | delete file; 27 | file = nullptr; 28 | } 29 | } 30 | 31 | bool CSVReader::open() { 32 | return (file != nullptr && file->is_open()); 33 | } 34 | 35 | CSVReader::~CSVReader() { 36 | stopReading(); 37 | } 38 | 39 | bool CSVReader::nextTrade() { 40 | return hasNextLine; 41 | } 42 | 43 | vector CSVReader::getTrade() { 44 | 45 | if (!nextTrade()) return vector(); 46 | 47 | vector temp; 48 | string line; 49 | line = currentLine; 50 | for(unsigned i = 0; i < line.length(); i++) { 51 | unsigned b = i; 52 | for(; line[i] != __CSV_DELIM && i + 1 != line.length(); i++); 53 | temp.push_back(line.substr(b, i - b)); 54 | } 55 | 56 | if ( !(file != nullptr && file->is_open() && getline(*file, currentLine)) ) { 57 | stopReading(); //close file or no more 58 | } 59 | 60 | return temp; 61 | } 62 | 63 | void CSVReader::stopReading() { 64 | hasNextLine = false; 65 | if (file != nullptr) { 66 | file->close(); 67 | delete file; 68 | file = nullptr; 69 | } 70 | 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/CSVReader.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSVReader.h 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | #ifndef __Algorithmic_Trading_CSVReader__ 10 | #define __Algorithmic_Trading_CSVReader__ 11 | 12 | namespace std { 13 | class CSVReader; 14 | } 15 | 16 | #include "GlobalIncludes.h" 17 | 18 | namespace std 19 | { 20 | class CSVReader 21 | { 22 | private: 23 | ifstream *file; 24 | bool hasNextLine; 25 | string currentLine; 26 | 27 | public: 28 | CSVReader(string dataFile, bool* foundFile); 29 | ~CSVReader(); 30 | bool open(); 31 | bool nextTrade(); 32 | vector getTrade(); 33 | void stopReading(); 34 | }; 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/CSVWriter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // CSVWriter.cpp 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | #include "CSVWriter.h" 10 | 11 | namespace std { 12 | 13 | CSVWriter::CSVWriter(string fileName) { 14 | output = new ofstream(fileName, ios::trunc); 15 | 16 | if (output->is_open()) { 17 | *output << "#Company, Date, Price, Volume, Value, Signal" << endl; 18 | isOpen = true; 19 | } else { 20 | isOpen = false; 21 | delete output; 22 | output = nullptr; 23 | } 24 | } 25 | 26 | 27 | bool CSVWriter::open() { 28 | return isOpen; 29 | } 30 | 31 | CSVWriter::~CSVWriter() { 32 | stopWriting(); 33 | } 34 | 35 | void CSVWriter::addCSVLine(string companyName, string date, double price, char signal) { 36 | if (isOpen) { 37 | stringstream ss; 38 | ss << companyName << __CSV_DELIM; 39 | ss << date << __CSV_DELIM; 40 | ss << setprecision(2) << std::fixed << price << __CSV_DELIM; 41 | ss << 100 << __CSV_DELIM; 42 | ss << setprecision(2) << std::fixed << 100 * price << __CSV_DELIM; 43 | ss << signal; 44 | *output << ss.str() << endl; 45 | } 46 | } 47 | 48 | void CSVWriter::stopWriting() { 49 | if (output != nullptr) { 50 | if(isOpen) output->close(); 51 | delete output; 52 | output = nullptr; 53 | } 54 | isOpen = false; 55 | } 56 | } 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/CSVWriter.h: -------------------------------------------------------------------------------- 1 | // 2 | // CSVWriter.h 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | #ifndef __Algorithmic_Trading_CSVWriter__ 10 | #define __Algorithmic_Trading_CSVWriter__ 11 | 12 | namespace std { 13 | class CSVWriter; 14 | } 15 | 16 | #include "GlobalIncludes.h" 17 | 18 | namespace std 19 | { 20 | class CSVWriter { 21 | private: 22 | bool isOpen; 23 | ofstream *output; 24 | public: 25 | CSVWriter(string dateFile); 26 | ~CSVWriter(); 27 | bool open(); 28 | //void startWriting(string dateFile); 29 | void stopWriting(); 30 | void addCSVLine(string companyName, string date, double price, char signal); 31 | }; 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/GlobalIncludes.h: -------------------------------------------------------------------------------- 1 | // 2 | // GlobalIncludes.h 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | #ifndef __Algorithmic_Trading__GlobalIncludes__ 10 | #define __Algorithmic_Trading__GlobalIncludes__ 11 | 12 | // define DEBUG for debugging (remove for production releases) 13 | #define DEBUG 0 14 | 15 | #define __PRODUCT_RELEASE_VERSION "2.00" 16 | 17 | #define __CSV_DELIM ((char)0x2c) 18 | 19 | #define __BUY_SIGNAL ((char)0x42) 20 | #define __SELL_SIGNAL ((char)0x53) 21 | 22 | #define __LOG_INFO 0 23 | #define __LOG_ERROR 1 24 | #define __LOG_DEBUG 2 25 | #define __LOG_FATAL 3 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | 36 | #ifdef _WIN32 //windows 32 and 64bit 37 | #include 38 | #else 39 | 40 | #ifdef __MACH__ //OS X 41 | #include 42 | #include 43 | 44 | #else //linux/unix 45 | #include 46 | #include 47 | #endif 48 | 49 | #endif 50 | 51 | namespace std { 52 | 53 | struct Date { 54 | int day; 55 | int month; 56 | int year; 57 | }; 58 | 59 | enum DateComparisonResult { 60 | dateSame, 61 | dateBefore, 62 | dateAfter, 63 | dateError 64 | }; 65 | 66 | class Helper { 67 | public: 68 | 69 | 70 | 71 | static Date parseDate(string dateStr) { 72 | 73 | Date date; 74 | date.day = -1; 75 | date.month = -1; 76 | date.year = -1; 77 | 78 | if (dateStr.size() == 11) { 79 | 80 | date.day = stoi(dateStr.substr(0,2).c_str()); 81 | date.year = stoi(dateStr.substr(7,4).c_str()); 82 | 83 | string strMonth = dateStr.substr(3, 3); 84 | if (strMonth.compare("JAN") == 0) 85 | date.month = 1; 86 | else if (strMonth.compare("FEB") == 0) 87 | date.month = 2; 88 | else if (strMonth.compare("MAR") == 0) 89 | date.month = 3; 90 | else if (strMonth.compare("APR") == 0) 91 | date.month = 4; 92 | else if (strMonth.compare("MAY") == 0) 93 | date.month = 5; 94 | else if (strMonth.compare("JUN") == 0) 95 | date.month = 6; 96 | else if (strMonth.compare("JUL") == 0) 97 | date.month = 7; 98 | else if (strMonth.compare("AUG") == 0) 99 | date.month = 8; 100 | else if (strMonth.compare("SEP") == 0) 101 | date.month = 9; 102 | else if (strMonth.compare("OCT") == 0) 103 | date.month = 10; 104 | else if (strMonth.compare("NOV") == 0) 105 | date.month = 11; 106 | else if (strMonth.compare("DEC") == 0) 107 | date.month = 12; 108 | } 109 | 110 | return date; 111 | } 112 | 113 | static DateComparisonResult compareDates(string dateRef, string dateComp) { 114 | 115 | Date ref = Helper::parseDate(dateRef); 116 | Date comp = Helper::parseDate(dateComp); 117 | 118 | if (comp.day == -1 || ref.day == -1 || comp.month == -1 || ref.month == -1 || comp.year == -1 || ref.year == -1) { 119 | return dateError; //error, date parse failed 120 | } 121 | 122 | if (comp.year == ref.year && comp.month == ref.month == comp.month && ref.day == comp.day) 123 | return dateSame; 124 | 125 | if (comp.year < ref.year || (comp.year == ref.year && (comp.month < ref.month || (comp.month == ref.month && comp.day < ref.day)) ) ) { 126 | return dateBefore; 127 | } 128 | 129 | return dateAfter; 130 | } 131 | 132 | static int daysInMonth(int month, int year) { 133 | month--; //change from 1-12 to 0-11 134 | int numberOfDays; 135 | if (month == 4 || month == 6 || month == 9 || month == 11) { 136 | numberOfDays = 30; 137 | } else if (month == 2) { 138 | bool isLeapYear = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); 139 | if (isLeapYear) 140 | numberOfDays = 29; 141 | else 142 | numberOfDays = 28; 143 | } else { 144 | numberOfDays = 31; 145 | } 146 | return numberOfDays; 147 | } 148 | 149 | //Returns a date as a string in format HH:MM:SS DD:MM:YYYY 150 | static string datetime() { 151 | time_t t = time(0); 152 | struct tm * now = localtime(&t); 153 | stringstream ss; 154 | ss << padDigit(now->tm_hour) << ':'; 155 | ss << padDigit(now->tm_min) << ':'; 156 | ss << padDigit(now->tm_sec) << ' '; 157 | ss << padDigit(now->tm_mday) << '/'; 158 | ss << padDigit(now->tm_mon + 1) << '/'; 159 | ss << now->tm_year + 1900; 160 | return ss.str(); 161 | } 162 | 163 | //Pad digits smaller than 10 with zeros to maintain length of components such as dates 164 | static inline string padDigit(int number) { 165 | return ((number < 10) ? ("0" + to_string(number)) : to_string(number)); 166 | } 167 | 168 | static string formatPrice(double price) { 169 | stringstream ss; 170 | ss << setprecision(2) << std::fixed << ((price < 0) ? "-$" : "$") << abs(price); 171 | return ss.str(); 172 | } 173 | static string formatDouble(double price) { 174 | stringstream ss; 175 | ss << setprecision(4) << std::fixed << price; 176 | return ss.str(); 177 | } 178 | 179 | static unsigned long sysTimeUS() { 180 | 181 | 182 | #ifdef _WIN32 //windows 32 and 64bit 183 | SYSTEMTIME st; 184 | GetSystemTime(&st); 185 | return (unsigned long)(st.wMilliseconds + (st.wSecond * 1000)); 186 | #else 187 | 188 | #ifdef __MACH__ //OS X 189 | struct timespec ts; 190 | clock_serv_t cclock; 191 | mach_timespec_t mts; 192 | host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); 193 | clock_get_time(cclock, &mts); 194 | mach_port_deallocate(mach_task_self(), cclock); 195 | ts.tv_sec = mts.tv_sec; 196 | ts.tv_nsec = mts.tv_nsec; 197 | return (unsigned long)(ts.tv_nsec + ts.tv_sec*1000000000L) / 1000; 198 | 199 | #else //linux/unix 200 | struct timespec ts; 201 | clock_gettime(CLOCK_REALTIME, &ts); 202 | return (unsigned long)(ts.tv_nsec + ts.tv_sec*1000000000L) / 1000; 203 | #endif 204 | 205 | #endif 206 | 207 | } 208 | }; 209 | } 210 | 211 | #endif 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /src/Logger.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Logger.cpp 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | #include "Logger.h" 10 | 11 | 12 | namespace std { 13 | 14 | Logger::Logger(string logFile, string csvFile, bool debug, string paramsDescr, string inputFileName) { 15 | 16 | this->logFile = nullptr; 17 | this->csvFile = nullptr; 18 | this->debug = debug; 19 | 20 | this->logFile = new ofstream(logFile, ios::trunc); 21 | this->csvFile = new CSVWriter(csvFile); 22 | 23 | if (!this->logFile->is_open()) { 24 | logError("Unable to write to log file: " + logFile, false); 25 | } 26 | 27 | if (!this->csvFile->open()) { 28 | logError("Unable to write to csv file: " + csvFile, false); 29 | } 30 | 31 | startTimeEpoch = Helper::sysTimeUS(); 32 | 33 | log("Trock: Version " __PRODUCT_RELEASE_VERSION); 34 | log("Antheny Yu, Ian Wong, Jason Ng, Mohammad Ghasembegi and Samuel Whitton"); 35 | log("Parameters parsed: " + paramsDescr); 36 | log("Input CSV file: " + inputFileName); 37 | log("Output Log file: " + logFile); 38 | log("Output CSV file: " + csvFile); 39 | log("Started Execution: " + Helper::datetime()); 40 | 41 | } 42 | 43 | Logger::~Logger() { 44 | stopLogging(); 45 | } 46 | 47 | 48 | 49 | void Logger::logDebug(string log) { 50 | if (debug) { 51 | cout << "[DEBUG] " + log << endl; 52 | } 53 | } 54 | 55 | void Logger::logError(string errorDescr, bool fatal) { 56 | if (fatal) { 57 | log("[FATAL ERROR] " + errorDescr); 58 | cout << "[FATAL ERROR] " + errorDescr << endl; 59 | stopLogging(); 60 | exit(1); 61 | } 62 | log("[ERROR] " + errorDescr); 63 | cout << "[ERROR] " + errorDescr << endl; 64 | } 65 | 66 | void Logger::log(string log) { 67 | 68 | if (logFile != nullptr && logFile->is_open()) { 69 | stringstream ss; 70 | ss << log; 71 | *logFile << log << endl; 72 | } 73 | } 74 | 75 | void Logger::writeToCSV(string companyName, string date, double price, char signal) { 76 | 77 | if (csvFile != nullptr && csvFile->open()) { 78 | csvFile->addCSVLine(companyName, date, price, signal); 79 | } 80 | } 81 | 82 | 83 | void Logger::stopLogging() { 84 | 85 | if (logFile != nullptr) { 86 | log("Ended Execution: " + Helper::datetime()); 87 | log("Elapsed Time: " + to_string(Helper::sysTimeUS() - startTimeEpoch) + " us"); 88 | 89 | if (logFile->is_open()) logFile->close(); 90 | delete logFile; 91 | logFile = nullptr; 92 | } 93 | 94 | if (csvFile != nullptr) { 95 | if (csvFile->open()) csvFile->stopWriting(); 96 | delete csvFile; 97 | csvFile = nullptr; 98 | } 99 | 100 | } 101 | 102 | } 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /src/Logger.h: -------------------------------------------------------------------------------- 1 | // 2 | // Logger.h 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | 10 | #ifndef __Algorithmic_Trading__Logger__ 11 | #define __Algorithmic_Trading__Logger__ 12 | 13 | 14 | namespace std { 15 | class Logger; 16 | } 17 | 18 | #include "GlobalIncludes.h" 19 | #include "CSVWriter.h" 20 | #include 21 | #include 22 | 23 | namespace std { 24 | 25 | 26 | class Logger { 27 | 28 | private: 29 | CSVWriter *csvFile; 30 | ofstream *logFile; 31 | bool debug; 32 | 33 | unsigned long startTimeEpoch; 34 | 35 | public: 36 | Logger(string logFile, string csvFile, bool debug, string paramsDescr, string inputFileName); 37 | ~Logger(); 38 | 39 | void stopLogging(); 40 | 41 | void logDebug(string log); 42 | void logError(string errorDescr, bool fatal); 43 | 44 | void log(string log); 45 | void writeToCSV(string companyName, string date, double price, char signal); 46 | 47 | 48 | }; 49 | 50 | } 51 | 52 | 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/MomentumStrategy.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // MomentumStrategy.cpp 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | #include "MomentumStrategy.h" 10 | 11 | 12 | namespace std { 13 | 14 | MomentumStrategy::MomentumStrategy(Logger &logger, string startDate, string endDate, unsigned int returnsInCalculation, double threshold) : 15 | super(logger, startDate, endDate), companyData() { 16 | this->defReturnsInCalculation = returnsInCalculation; 17 | this->defThreshold = threshold; 18 | } 19 | 20 | MomentumStrategyData *MomentumStrategy::dataForTradeDay(TradeDay tradeDay) { 21 | if (companyData.find(tradeDay.getCompany()) == companyData.end()) { 22 | companyData[tradeDay.getCompany()] = MomentumStrategyData(defThreshold, defReturnsInCalculation); 23 | } 24 | MomentumStrategyData *data = &companyData[tradeDay.getCompany()]; 25 | return data; 26 | } 27 | 28 | int MomentumStrategy::nextTradeDay(TradeDay tradeDay, bool enableBuyTrades, bool enableSellTrades, double thresholdBias, int forcedSignal) { 29 | 30 | int signalSignaled = -1; 31 | 32 | if (companyData.find(tradeDay.getCompany()) == companyData.end()) { 33 | companyData[tradeDay.getCompany()] = MomentumStrategyData(defThreshold, defReturnsInCalculation); 34 | } 35 | MomentumStrategyData *data = &companyData[tradeDay.getCompany()]; 36 | double thisPrice = tradeDay.getLastPrice(); 37 | data->lastTradeDaysAgo++; 38 | logger.logDebug(""); 39 | double Rt = 0.0; 40 | 41 | //return calculation 42 | if (data->previousPrice == 0.0) { 43 | logger.logDebug("Rt: 0.0"); 44 | } else { 45 | Rt = (thisPrice - data->previousPrice) / data->previousPrice; 46 | logger.logDebug("Rt: " + Helper::formatDouble(Rt)); 47 | data->returns.push_back(Rt); 48 | data->priceAtReturn.push_back(thisPrice); 49 | } 50 | 51 | //SMA calculation 52 | if (data->returns.size() < data->returnsInCalculation) { 53 | logger.logDebug("SMAt: 0.0"); 54 | } else { 55 | //enough returns to start calculating moving average 56 | double sumRt = 0.0; 57 | for (unsigned long i = data->returns.size() - data->returnsInCalculation; i < data->returns.size(); i++) { 58 | sumRt += data->returns[i]; 59 | } 60 | double SMAt = sumRt / data->returnsInCalculation; 61 | logger.logDebug("SMAt: " + Helper::formatDouble(SMAt)); 62 | 63 | if (data->lastHadMovingAverage) { 64 | double diff = SMAt - data->lastMovingAverage + thresholdBias; 65 | 66 | bool enableTrading = enableBuyTrades || enableSellTrades; 67 | if (enableTrading) { 68 | 69 | if ((diff > data->threshold || forcedSignal == __BUY_SIGNAL) && enableBuyTrades) { 70 | logger.logDebug("Buy Signal"); 71 | if(data->previousSignal != __BUY_SIGNAL) { 72 | signalSignaled = __BUY_SIGNAL; 73 | data->previousPriceOnSignal = thisPrice; 74 | data->lastSignalOdd = !data->lastSignalOdd; 75 | data->lastTradeDaysAgo = 0; 76 | data->previousSignal = __BUY_SIGNAL; 77 | logger.writeToCSV(tradeDay.getCompany(), tradeDay.getDate(), tradeDay.getLastPrice(), __BUY_SIGNAL); 78 | } else logger.logDebug("Ignored Signal"); 79 | } else if ((diff < -data->threshold || forcedSignal == __SELL_SIGNAL) && enableSellTrades) { 80 | logger.logDebug("Sell Signal"); 81 | if(data->previousSignal != __SELL_SIGNAL) { 82 | signalSignaled = __SELL_SIGNAL; 83 | data->previousPriceOnSignal = thisPrice; 84 | data->lastSignalOdd = !data->lastSignalOdd; 85 | data->lastTradeDaysAgo = 0; 86 | data->previousSignal = __SELL_SIGNAL; 87 | logger.writeToCSV(tradeDay.getCompany(), tradeDay.getDate(), tradeDay.getLastPrice(), __SELL_SIGNAL); 88 | } else logger.logDebug("Ignored Signal"); 89 | 90 | } else { 91 | logger.logDebug("Ignored Signal"); 92 | } 93 | 94 | } 95 | } 96 | 97 | data->lastHadMovingAverage = true; 98 | data->lastMovingAverage = SMAt; 99 | } 100 | 101 | 102 | data->previousPrice = thisPrice; 103 | 104 | return signalSignaled; 105 | } 106 | 107 | void MomentumStrategy::nextTradeDay(TradeDay tradeDay, bool enableTrading) { 108 | nextTradeDay(tradeDay, enableTrading, enableTrading, 0.0, -1); 109 | } 110 | 111 | 112 | } 113 | 114 | 115 | -------------------------------------------------------------------------------- /src/MomentumStrategy.h: -------------------------------------------------------------------------------- 1 | // 2 | // MomentumStrategy.h 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | 10 | #ifndef __Algorithmic_Trading__MomentumStrategy__ 11 | #define __Algorithmic_Trading__MomentumStrategy__ 12 | 13 | namespace std { 14 | class MomentumStrategy; 15 | } 16 | 17 | #include "GlobalIncludes.h" 18 | 19 | #include 20 | 21 | #include "Strategy.h" 22 | #include "MomentumStrategyData.h" 23 | 24 | 25 | namespace std { 26 | 27 | 28 | class MomentumStrategy : public Strategy { 29 | 30 | private: 31 | typedef Strategy super; 32 | 33 | map companyData; 34 | 35 | double defThreshold; 36 | unsigned int defReturnsInCalculation; //number of returns to use in equation (n from spec) 37 | 38 | protected: 39 | //if forced signal != buy of sell, then ignore 40 | int nextTradeDay(TradeDay tradeDay, bool enableBuyTrades, bool enableSellTrades, double thresholdBias, int forcedSignal); //returns signal 41 | virtual void nextTradeDay(TradeDay tradeDay, bool enableTrading); 42 | 43 | //call has no effect on this object, also treat data as read only! 44 | //also this is a valid pointer until ANY mutating call to this object is made 45 | MomentumStrategyData *dataForTradeDay(TradeDay tradeDay); 46 | 47 | 48 | 49 | public: 50 | MomentumStrategy(Logger &logger, string startDate, string endDate, unsigned int returnsInCalculation, double threshold); 51 | 52 | }; 53 | 54 | } 55 | 56 | 57 | 58 | #endif 59 | 60 | -------------------------------------------------------------------------------- /src/MomentumStrategyData.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // MomentumStrategyData.cpp 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | #include "MomentumStrategyData.h" 10 | 11 | 12 | namespace std { 13 | 14 | MomentumStrategyData::MomentumStrategyData() : MomentumStrategyData(0.0, 0) {} 15 | 16 | MomentumStrategyData::MomentumStrategyData(double threshold, unsigned int returnsInCalculation) { 17 | this->lastHadMovingAverage = false; 18 | previousSignal = -1; 19 | previousPriceOnSignal = 0.0; 20 | lastSignalOdd = false; 21 | lastTradeDaysAgo = 0; 22 | previousPrice = 0.0; 23 | returns = vector(); 24 | priceAtReturn = vector(); 25 | this->threshold = threshold; 26 | this->returnsInCalculation = returnsInCalculation; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/MomentumStrategyData.h: -------------------------------------------------------------------------------- 1 | // 2 | // MomentumStrategyData.h 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | 10 | #ifndef __Algorithmic_Trading__MomentumStrategyData__ 11 | #define __Algorithmic_Trading__MomentumStrategyData__ 12 | 13 | namespace std { 14 | class MomentumStrategyData; 15 | } 16 | 17 | #include "GlobalIncludes.h" 18 | 19 | 20 | namespace std { 21 | 22 | 23 | class MomentumStrategyData { 24 | 25 | public: 26 | MomentumStrategyData(); 27 | MomentumStrategyData(double threshold, unsigned int returnsInCalculation); 28 | int previousSignal; 29 | double previousPriceOnSignal; 30 | double previousPrice; 31 | int lastTradeDaysAgo; 32 | bool lastSignalOdd; 33 | vector returns; 34 | vector priceAtReturn; 35 | bool lastHadMovingAverage; 36 | double lastMovingAverage; 37 | double threshold; 38 | unsigned int returnsInCalculation; 39 | }; 40 | 41 | } 42 | 43 | 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/MutantFrogStrategy.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // MutantFrogStrategy.cpp 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | #include "MutantFrogStrategy.h" 10 | 11 | 12 | #define INITIAL_RETURNS_IN_CALCULATION MIN_RETURNS_IN_CALCULATION 13 | #define INITIAL_THRESHOLD 0.001 //arbitrary 14 | 15 | #define RETURNS_WINDOW_MOD 0.78 16 | 17 | #define THRESHOLD_PERCENT_RANGE 0.1 18 | 19 | #define MIN_RETURNS_IN_CALCULATION 7 20 | #define RETURNS_DIFFERENCE_PERCENT 0.35 21 | 22 | #define EQUITY_LOSS_PERCENT_ALLOWANCE 0.035 23 | 24 | namespace std { 25 | 26 | MutantFrogStrategy::MutantFrogStrategy(Logger &logger, string startDate, string endDate, double threshold) : 27 | super(logger, startDate, endDate, INITIAL_RETURNS_IN_CALCULATION, threshold), influences() {} 28 | 29 | void MutantFrogStrategy::nextTradeDay(TradeDay tradeDay, bool enableTrading) { 30 | 31 | double thisPrice = tradeDay.getLastPrice(); 32 | 33 | MomentumStrategyData *superData = super::dataForTradeDay(tradeDay); 34 | 35 | //enable on odd trades 36 | bool enableBuyTrades = enableTrading && !superData->lastSignalOdd; 37 | 38 | //dont enable selling on first trade, and enable on all even trades 39 | bool enableSellTrades = enableTrading && superData->lastSignalOdd; 40 | 41 | 42 | //inc returns in calc 43 | //if (superData->returnsInCalculation <= (int)superData->returns.size()) { 44 | // superData->returnsInCalculation += 1; 45 | //} 46 | 47 | //if (!superData->lastSignalOdd && superData->returns.size() >= MIN_RETURNS_IN_CALCULATION) { 48 | // superData->returnsInCalculation = MIN_RETURNS_IN_CALCULATION; 49 | //} 50 | 51 | //sum returns and check if we should move avg window to 2/3rd of current window 52 | //only before the odd trade 53 | /*if (!superData->lastSignalOdd && superData->returns.size() >= MIN_RETURNS_IN_CALCULATION) { 54 | 55 | int thirdOfReturnWindow = superData->returnsInCalculation / 3; 56 | 57 | double recentThirdSumRt = 0.0; 58 | double firstThirdSumRt = 0.0; 59 | for (unsigned long i = superData->returns.size() - thirdOfReturnWindow; i < superData->returns.size(); i++) { 60 | recentThirdSumRt += superData->returns[i]; 61 | } 62 | for (unsigned long i = 0; i < thirdOfReturnWindow; i++) { 63 | firstThirdSumRt += superData->returns[i]; 64 | } 65 | 66 | double currentThirdChangePercent = recentThirdSumRt / firstThirdSumRt - 1.0; 67 | if (currentThirdChangePercent > RETURNS_DIFFERENCE_PERCENT || currentThirdChangePercent < -RETURNS_DIFFERENCE_PERCENT) { 68 | superData->returnsInCalculation = thirdOfReturnWindow * 2; 69 | } 70 | 71 | }*/ 72 | 73 | /*if (superData->returns.size() >= MIN_RETURNS_IN_CALCULATION) { 74 | //calculate threshold based on max and min and avg in returns window 75 | double wTotalPrice = 0.0; 76 | double wMinPrice = 0.0, wMaxPrice = 0.0; 77 | for (unsigned long i = superData->priceAtReturn.size() - superData->returnsInCalculation; i < superData->priceAtReturn.size(); i++) { 78 | double thisPrice = superData->priceAtReturn[i]; 79 | wTotalPrice += thisPrice; 80 | if (i == superData->priceAtReturn.size() - superData->returnsInCalculation) { 81 | //first price 82 | wMinPrice = thisPrice; 83 | wMaxPrice = thisPrice; 84 | } else { 85 | if (thisPrice > wMaxPrice) { 86 | wMaxPrice = thisPrice; 87 | } 88 | if (thisPrice < wMinPrice) { 89 | wMinPrice = thisPrice; 90 | } 91 | } 92 | } 93 | double wAvgPrice = wTotalPrice / superData->returnsInCalculation; 94 | if (enableBuyTrades) { 95 | superData->threshold = THRESHOLD_PERCENT_RANGE * ((wMaxPrice - wAvgPrice) / wAvgPrice); 96 | } else { 97 | superData->threshold = THRESHOLD_PERCENT_RANGE * ((wAvgPrice - wMinPrice) / wAvgPrice); 98 | } 99 | cout << superData->threshold << "\n"; 100 | }*/ 101 | 102 | 103 | bool forcedTradeMade = false; 104 | 105 | //manage the risk for allowance only on the even trade 106 | if (superData->lastSignalOdd && (superData->previousSignal == __BUY_SIGNAL || superData->previousSignal == __SELL_SIGNAL)) { 107 | 108 | double tradeDirection = (superData->previousSignal == __SELL_SIGNAL) ? -1.0 : 1.0; 109 | 110 | double negativePriceMovement = superData->previousPriceOnSignal / thisPrice - 1.0; 111 | 112 | //if (tradeDirection * negativePriceMovement > EQUITY_LOSS_PERCENT_ALLOWANCE 113 | //|| ( tradeDirection*(superData->previousPriceOnSignal - superData->previousPrice) > 0.0 114 | //&& tradeDirection*(superData->previousPrice - thisPrice) > 0.0 )) { 115 | 116 | if (tradeDirection * negativePriceMovement > EQUITY_LOSS_PERCENT_ALLOWANCE) { 117 | 118 | forcedTradeMade = true; 119 | if (superData->previousSignal == __BUY_SIGNAL) { 120 | super::nextTradeDay(tradeDay, enableBuyTrades, enableSellTrades, 0.0, __SELL_SIGNAL); 121 | } else { 122 | super::nextTradeDay(tradeDay, enableBuyTrades, enableSellTrades, 0.0, __BUY_SIGNAL); 123 | } 124 | 125 | } 126 | 127 | 128 | 129 | } 130 | 131 | bool madeTrade = forcedTradeMade; 132 | 133 | if (!forcedTradeMade) { 134 | //biased based on threshold and influences 135 | double threshBias = superData->threshold * influences.tradeDayInfluence(tradeDay); 136 | int signal = super::nextTradeDay(tradeDay, enableBuyTrades, enableSellTrades, threshBias, -1); 137 | madeTrade = (madeTrade || signal == __BUY_SIGNAL || signal == __SELL_SIGNAL); 138 | } 139 | 140 | if (madeTrade) { 141 | superData->returnsInCalculation = (int)((double)superData->lastTradeDaysAgo * RETURNS_WINDOW_MOD); 142 | if (superData->returnsInCalculation < MIN_RETURNS_IN_CALCULATION) { 143 | superData->returnsInCalculation = MIN_RETURNS_IN_CALCULATION; 144 | } 145 | } 146 | } 147 | 148 | 149 | } 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /src/MutantFrogStrategy.h: -------------------------------------------------------------------------------- 1 | // 2 | // MutantFrogStrategy.h 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 05/05/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | 10 | #ifndef __Algorithmic_Trading__MutantFrogStrategy__ 11 | #define __Algorithmic_Trading__MutantFrogStrategy__ 12 | 13 | namespace std { 14 | class MutantFrogStrategy; 15 | } 16 | 17 | #include "GlobalIncludes.h" 18 | 19 | #include "MomentumStrategy.h" 20 | #include "TradingInfluences.h" 21 | 22 | 23 | namespace std { 24 | 25 | 26 | class MutantFrogStrategy : public MomentumStrategy { 27 | 28 | private: 29 | typedef MomentumStrategy super; 30 | 31 | TradingInfluences influences; 32 | 33 | protected: 34 | virtual void nextTradeDay(TradeDay tradeDay, bool enableTrading); 35 | 36 | public: 37 | MutantFrogStrategy(Logger &logger, string startDate, string endDate, double threshold); 38 | 39 | }; 40 | 41 | } 42 | 43 | 44 | 45 | #endif 46 | 47 | -------------------------------------------------------------------------------- /src/Params.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Params.cpp 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | #include "Params.h" 10 | 11 | #define __PARAM_DELIM ((char)0x5C) //"\" 12 | #define __PARAM_ID_START ((char)0x3A) //":" 13 | #define __PARAM_VALUE_START ((char)0x3A) //":" 14 | 15 | 16 | namespace std { 17 | 18 | Params::Params(string paramFileDir, bool *foundFile) : params() { 19 | 20 | ifstream paramFile(paramFileDir, ios::in); 21 | *foundFile = false; 22 | 23 | if (paramFile.is_open()) { 24 | *foundFile = true; 25 | 26 | //parsing setup 27 | bool waitingForIdStart = true; //waiting for initial start character 28 | bool readingParamId = true; 29 | bool lastCharWasDelim = false; 30 | string currentParamId = ""; 31 | string currentParamBody = ""; 32 | 33 | int ic = paramFile.get(); 34 | while (ic != EOF) { 35 | char c = (char)ic; 36 | 37 | //do nothing in the interum of waiting for start character 38 | if (waitingForIdStart) { 39 | if (c == __PARAM_ID_START) { 40 | waitingForIdStart = false; 41 | readingParamId = true; 42 | } 43 | ic = paramFile.get(); 44 | continue; 45 | } 46 | 47 | if (readingParamId) { 48 | if (c == __PARAM_VALUE_START) { 49 | readingParamId = false; 50 | } else { 51 | currentParamId.append(1, c); 52 | } 53 | } else { 54 | 55 | //delim; double delim = use as character, single = forget, new character after delim then add param 56 | if (lastCharWasDelim) { 57 | lastCharWasDelim = false; 58 | if (c != __PARAM_DELIM) { 59 | addParam(currentParamId, currentParamBody); 60 | currentParamId = ""; 61 | currentParamBody = ""; 62 | waitingForIdStart = true; 63 | } else { 64 | currentParamBody.append(1, c); 65 | } 66 | } else if (c == __PARAM_DELIM) { 67 | lastCharWasDelim = true; 68 | 69 | } else { 70 | currentParamBody.append(1, c); 71 | } 72 | 73 | } 74 | 75 | ic = paramFile.get(); 76 | } 77 | 78 | //add param at end of file 79 | if (lastCharWasDelim) { 80 | addParam(currentParamId, currentParamBody); 81 | } 82 | 83 | paramFile.close(); 84 | 85 | } 86 | } 87 | 88 | 89 | void Params::addParam(string paramId, string paramValue) { 90 | 91 | Param param; 92 | param.isNull = false; 93 | param.stringVal = paramValue; 94 | 95 | //defaults 96 | param.intVal = -1; 97 | param.doubleVal = -1; 98 | param.isNumber = false; 99 | 100 | try { 101 | string::size_type sz; 102 | double dval = stod(paramValue, &sz); 103 | param.isNumber = true; 104 | param.doubleVal = dval; 105 | param.intVal = static_cast(round(dval)); 106 | 107 | } catch (invalid_argument) { 108 | } catch (out_of_range) {} 109 | 110 | params[paramId] = param; 111 | } 112 | 113 | string Params::paramList() { 114 | string pList = ""; 115 | 116 | string join = ""; 117 | for (auto &p : params) { 118 | pList += join + p.first; 119 | join = ", "; 120 | } 121 | 122 | return pList; 123 | } 124 | 125 | 126 | Param Params::getParam(string paramId) { 127 | 128 | if (params.find(paramId) == params.end()) { 129 | return nullParam(); 130 | } 131 | 132 | return params[paramId]; 133 | } 134 | 135 | Param Params::nullParam() { 136 | Param np; 137 | np.isNull = true; 138 | return np; 139 | } 140 | 141 | 142 | } 143 | -------------------------------------------------------------------------------- /src/Params.h: -------------------------------------------------------------------------------- 1 | // 2 | // Params.h 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | 10 | #ifndef __Algorithmic_Trading__Params__ 11 | #define __Algorithmic_Trading__Params__ 12 | 13 | namespace std { 14 | class Params; 15 | } 16 | 17 | #include "GlobalIncludes.h" 18 | 19 | #include 20 | 21 | 22 | namespace std { 23 | 24 | struct Param { 25 | bool isNull; 26 | bool isNumber; 27 | 28 | string stringVal; 29 | int intVal; 30 | double doubleVal; 31 | }; 32 | 33 | class Params { 34 | 35 | private: 36 | map params; 37 | void addParam(string paramId, string paramValue); 38 | 39 | public: 40 | Params(string paramFileDir, bool *foundFile); 41 | Param getParam(string paramId); 42 | string paramList(); 43 | static Param nullParam(); 44 | }; 45 | 46 | } 47 | 48 | 49 | 50 | #endif 51 | 52 | -------------------------------------------------------------------------------- /src/Strategy.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Strategy.cpp 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | #include "Strategy.h" 10 | 11 | 12 | namespace std { 13 | 14 | Strategy::Strategy(Logger &logger, string startDate, string endDate) : 15 | logger(logger), dStart(startDate), dEnd(endDate) {} 16 | 17 | 18 | 19 | StrategyResult Strategy::nextDay(TradeDay tradeDay) { 20 | 21 | bool shouldTrade = true; 22 | 23 | DateComparisonResult compareStart = Helper::compareDates(dStart, tradeDay.getDate()); 24 | DateComparisonResult compareEnd = Helper::compareDates(dEnd, tradeDay.getDate()); 25 | 26 | if (compareStart == dateError || compareEnd == dateError) { 27 | logger.logError("Date parsing error.", true); 28 | } 29 | 30 | if (compareStart == dateBefore || compareEnd == dateAfter) { 31 | shouldTrade = false; 32 | } 33 | 34 | //just incase, trade always 35 | if (dStart.compare("") == 0 || dEnd.compare("") == 0 36 | || tradeDay.getDate().compare("") == 0) 37 | shouldTrade = true; 38 | 39 | nextTradeDay(tradeDay, shouldTrade); 40 | return StrategyResult::nullResult(); 41 | } 42 | 43 | 44 | } 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/Strategy.h: -------------------------------------------------------------------------------- 1 | // 2 | // Strategy.h 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | 10 | #ifndef __Algorithmic_Trading__Strategy__ 11 | #define __Algorithmic_Trading__Strategy__ 12 | 13 | namespace std { 14 | class Strategy; 15 | } 16 | 17 | #include "GlobalIncludes.h" 18 | 19 | #include "Logger.h" 20 | #include "StrategyResult.h" 21 | #include "TradeDay.h" 22 | 23 | 24 | namespace std { 25 | 26 | 27 | class Strategy { 28 | 29 | private: 30 | string dStart, dEnd; 31 | 32 | protected: 33 | Logger &logger; 34 | 35 | virtual void nextTradeDay(TradeDay tradeDay, bool enableTrading) = 0; // to be implemented (template) 36 | 37 | 38 | public: 39 | Strategy(Logger &logger, string startDate, string endDate); 40 | StrategyResult nextDay(TradeDay tradeDay); 41 | 42 | }; 43 | 44 | } 45 | 46 | 47 | 48 | #endif 49 | 50 | -------------------------------------------------------------------------------- /src/StrategyResult.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // StrategyResult.cpp 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | #include "StrategyResult.h" 10 | 11 | 12 | namespace std { 13 | 14 | StrategyResult::StrategyResult() { 15 | isNullResult = true; 16 | transferAmount = 0.0; 17 | type = ResultType::Nothing; 18 | } 19 | 20 | StrategyResult::StrategyResult(ResultType type, double equityTransfer) { 21 | isNullResult = false; 22 | transferAmount = equityTransfer; 23 | this->type = type; 24 | } 25 | 26 | StrategyResult StrategyResult::nullResult() { 27 | return StrategyResult(); 28 | } 29 | 30 | 31 | bool StrategyResult::isNull() { 32 | return isNullResult; 33 | } 34 | 35 | string StrategyResult::description() { 36 | if (isNull()) 37 | return "NULL"; 38 | if (type == Nothing) 39 | return "Dont buy or sell"; 40 | string actDescr = "Sell"; 41 | if (type == Buy) 42 | actDescr = "Buy"; 43 | 44 | if (transferAmount != 0.0) { 45 | return actDescr + " " + Helper::formatPrice(transferAmount) + " of equity"; 46 | } 47 | return actDescr + " equity"; 48 | } 49 | 50 | } 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/StrategyResult.h: -------------------------------------------------------------------------------- 1 | // 2 | // StrategyResult.h 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | 10 | #ifndef __Algorithmic_Trading__StrategyResult__ 11 | #define __Algorithmic_Trading__StrategyResult__ 12 | 13 | namespace std { 14 | class StrategyResult; 15 | } 16 | 17 | #include "GlobalIncludes.h" 18 | 19 | 20 | 21 | namespace std { 22 | 23 | typedef enum : int { 24 | Buy, 25 | Sell, 26 | Nothing 27 | } ResultType; 28 | 29 | class StrategyResult { 30 | 31 | private: 32 | StrategyResult(); 33 | StrategyResult(ResultType type, double equityTransfer); 34 | 35 | bool isNullResult; 36 | 37 | ResultType type; 38 | double transferAmount; 39 | 40 | public: 41 | 42 | static StrategyResult nullResult(); 43 | 44 | /*static StrategyResult buyEquity(); 45 | static StrategyResult sellEquity(); 46 | static StrategyResult buyEquity(double amount); 47 | static StrategyResult sellEquity(double amount); 48 | static StrategyResult doNothing();*/ 49 | 50 | bool isNull(); 51 | string description(); 52 | 53 | }; 54 | 55 | } 56 | 57 | 58 | 59 | #endif 60 | 61 | -------------------------------------------------------------------------------- /src/TradeDay.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // TradeDay.cpp 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | #include "TradeDay.h" 10 | 11 | 12 | namespace std { 13 | 14 | TradeDay::TradeDay(double openPrice, double highPrice, double lowPrice, double lastPrice, string company, string date) { 15 | this->openPrice = openPrice; 16 | this->highPrice = highPrice; 17 | this->lowPrice = lowPrice; 18 | this->lastPrice = lastPrice; 19 | this->company = company; 20 | this->date = date; 21 | } 22 | 23 | double TradeDay::getOpenPrice() { 24 | return openPrice; 25 | } 26 | 27 | double TradeDay::getHighPrice() { 28 | return highPrice; 29 | } 30 | 31 | double TradeDay::getLowPrice() { 32 | return lowPrice; 33 | } 34 | 35 | double TradeDay::getLastPrice() { 36 | return lastPrice; 37 | } 38 | 39 | string TradeDay::getDate() { 40 | return date; 41 | } 42 | string TradeDay::getCompany() { 43 | return company; 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/TradeDay.h: -------------------------------------------------------------------------------- 1 | // 2 | // TradeDay.h 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | 10 | #ifndef __Algorithmic_Trading__TradeDay__ 11 | #define __Algorithmic_Trading__TradeDay__ 12 | 13 | namespace std { 14 | class TradeDay; 15 | } 16 | 17 | #include "GlobalIncludes.h" 18 | 19 | 20 | namespace std { 21 | 22 | 23 | class TradeDay { 24 | 25 | private: 26 | double lastPrice; 27 | double openPrice; 28 | double highPrice; 29 | double lowPrice; 30 | string company; 31 | string date; 32 | 33 | public: 34 | TradeDay(double openPrice, double highPrice, double lowPrice, double lastPrice, string company, string date); 35 | double getLastPrice(); 36 | double getLowPrice(); 37 | double getHighPrice(); 38 | double getOpenPrice(); 39 | string getDate(); 40 | string getCompany(); 41 | 42 | }; 43 | 44 | } 45 | 46 | 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/TradingInfluences.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // TradingInfluences.cpp 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | #include "TradingInfluences.h" 10 | 11 | 12 | namespace std { 13 | 14 | TradingInfluences::TradingInfluences() { 15 | 16 | } 17 | 18 | //-1.0 (most sell influence) to 1.0 (most buy influence) 19 | double TradingInfluences::tradeDayInfluence(TradeDay tradeDay) { 20 | return 0.0; //default no influence 21 | } 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/TradingInfluences.h: -------------------------------------------------------------------------------- 1 | // 2 | // TradingInfluences.h 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 05/05/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | 10 | #ifndef __Algorithmic_Trading__TradingInfluences__ 11 | #define __Algorithmic_Trading__TradingInfluences__ 12 | 13 | namespace std { 14 | class TradingInfluences; 15 | } 16 | 17 | #include "GlobalIncludes.h" 18 | 19 | #include "TradeDay.h" 20 | 21 | 22 | namespace std { 23 | 24 | 25 | class TradingInfluences { 26 | 27 | public: 28 | TradingInfluences(); 29 | 30 | //-1.0 (most sell influence) to 1.0 (most buy influence) 31 | double tradeDayInfluence(TradeDay tradeDay); 32 | 33 | }; 34 | 35 | } 36 | 37 | 38 | 39 | #endif 40 | 41 | -------------------------------------------------------------------------------- /src/UnitTester.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // UnitTester.cpp 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 24/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | #include "UnitTester.h" 10 | #include "GlobalIncludes.h" 11 | #include "Strategy.h" 12 | #include "StrategyResult.h" 13 | #include "Logger.h" 14 | 15 | #include 16 | 17 | namespace std 18 | { 19 | //Function Declarations 20 | bool testGlobalIncludes(); 21 | bool testStrategyResult(); 22 | 23 | UnitTester::UnitTester() {} 24 | 25 | //Test all components using this function 26 | bool UnitTester::testAll() { 27 | assert(testGlobalIncludes()); 28 | assert(testStrategyResult()); 29 | return true; 30 | } 31 | 32 | //GlobalIncludes.h 33 | bool testGlobalIncludes() { 34 | //Test Formating functions 35 | 36 | //Price format 37 | assert(Helper::formatPrice(0) == "$0.00"); 38 | assert(Helper::formatPrice(1) == "$1.00"); 39 | assert(Helper::formatPrice(2.33) == "$2.33"); 40 | assert(Helper::formatPrice(-500.88) == "-$500.88"); 41 | assert(Helper::formatPrice(-20.3041) == "-$20.30"); //round down 42 | assert(Helper::formatPrice(-20.3061) == "-$20.31"); //round up 43 | 44 | //Double format 45 | assert(Helper::formatDouble(0) == "0.0000"); 46 | assert(Helper::formatDouble(1) == "1.0000"); 47 | assert(Helper::formatDouble(2.33) == "2.3300"); 48 | assert(Helper::formatDouble(-500.88) == "-500.8800"); 49 | assert(Helper::formatDouble(-2344.5673) == "-2344.5673"); 50 | assert(Helper::formatDouble(345465.23423546) == "345465.2342"); 51 | 52 | return true; 53 | } 54 | 55 | //StrategyResult 56 | bool testStrategyResult() { 57 | assert(StrategyResult::nullResult().isNull()); //check static nullResult is actually null 58 | return true; 59 | } 60 | } -------------------------------------------------------------------------------- /src/UnitTester.h: -------------------------------------------------------------------------------- 1 | // 2 | // UnitTester.h 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 24/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | #ifndef __Algorithmic_Trading__UnitTester__ 10 | #define __Algorithmic_Trading__UnitTester__ 11 | 12 | //Includes 13 | #include 14 | 15 | namespace std 16 | { 17 | class UnitTester 18 | { 19 | 20 | public: 21 | UnitTester(); // Constructor 22 | 23 | /* 24 | * Returns true if all components passed all tests. False otherwise. 25 | */ 26 | bool testAll(); // Test all components 27 | }; 28 | } 29 | 30 | #endif -------------------------------------------------------------------------------- /src/example.param: -------------------------------------------------------------------------------- 1 | 2 | //The input csv file detailing the price of equity each day 3 | :input_csvFile:../sample_data_file.csv\ 4 | 5 | //output csv file 6 | :output_csvFile:BHP.csv\ 7 | 8 | //the output log file 9 | :output_logFile:AlgorithmicTrading.log\ 10 | 11 | //an integer detailing the returns used in the moving average 12 | //calculation (from spec) 13 | :returnsInCalculation:3\ 14 | 15 | //a decimal >= 0, smaller means more likely to buy and sell 16 | :threshold:0.005\ -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // main.cpp 3 | // Algorithmic Trading SENG3011 4 | // 5 | // Created on 03/03/15. 6 | // Copyright (c) Trock. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | 12 | #include "GlobalIncludes.h" 13 | #include "MomentumStrategy.h" 14 | #include "Logger.h" 15 | #include "TradeDay.h" 16 | #include "Params.h" 17 | #include "CSVReader.h" 18 | #include "UnitTester.h" 19 | #include "MutantFrogStrategy.h" 20 | 21 | void run(std::Logger &logger, std::CSVReader &reader, std::Strategy *strategy) { 22 | while(reader.nextTrade()) { 23 | std::vector temp = reader.getTrade(); 24 | if(temp.at(4).compare("No Trades") == 0) continue; 25 | try { 26 | double lastPrice = std::stod(temp.at(8)); 27 | double lowPrice = std::stod(temp.at(7)); 28 | double highPrice = std::stod(temp.at(6)); 29 | double openPrice = std::stod(temp.at(5)); 30 | std::TradeDay trade(openPrice, highPrice, lowPrice, lastPrice, temp.at(0), temp.at(1)); 31 | strategy->nextDay(trade); 32 | } catch(std::invalid_argument) {} 33 | } 34 | } 35 | 36 | int main(int argc, const char * argv[]) { 37 | 38 | int returnsValue = 4; 39 | double thresholdValue = 0.001; 40 | 41 | #ifdef DEBUG 42 | std::UnitTester tester; 43 | tester.testAll(); 44 | #endif // DEBUG 45 | 46 | // Ensure we have the corrent number of arguments 47 | // or the nasty seg fault monster will come and steal all the sugar 48 | if(argc < 2) { 49 | std::cerr << "usage: " << argv[0] << " [parameter file]" << std::endl; 50 | return 0; 51 | } 52 | 53 | //Check to see if we can find parameter file 54 | bool foundFile; 55 | std::Params parameters(argv[argc - 1], &foundFile); 56 | if(!foundFile) { 57 | std::cerr << "Fatal Error: The parameter file was not found." << std::endl; 58 | return 0; 59 | } 60 | 61 | //Check to see if outputLogfile exists 62 | std::Param outputLogFile = parameters.getParam("output_logFile"); 63 | if(outputLogFile.isNull) { 64 | std::cerr << "Fatal Error: Failed to load file specified in 'output_logFile' parameter." << std::endl; 65 | return 0; 66 | } 67 | 68 | //Check to see if csv file exists 69 | std::Param outputCSVFile = parameters.getParam("output_csvFile"); 70 | if(outputCSVFile.isNull) { 71 | std::cerr << "Fatal Error: Failed to load file specified in 'output_csvFile' parameter." << std::endl; 72 | return 0; 73 | } 74 | 75 | //Check to see if input csv file exists 76 | std::Param inputCSVFile = parameters.getParam("input_csvFile"); 77 | if (inputCSVFile.isNull) { 78 | std::cerr << "Fatal Error: Failed to load file specified in 'input_csvFile' parameter." << std::endl; 79 | return 0; 80 | } 81 | 82 | //Check if outputCSV is equal to inputCSV and fail if it is (to prevent overwriting input) 83 | if (outputCSVFile.stringVal.compare(inputCSVFile.stringVal) == 0) { 84 | std::cerr << "Fatal Error: 'input_csvFile' parameter and 'output_csvFile' parameter must be different." << std::endl; 85 | return 0; 86 | } 87 | 88 | //Check if outputLog is the inputCSV file (we don't want to output csv to the log file) 89 | if (outputLogFile.stringVal.compare(inputCSVFile.stringVal) == 0) { 90 | std::cerr << "Fatal Error: 'input_csvFile' parameter and 'output_logFile' parameter must be different." << std::endl; 91 | return 0; 92 | } 93 | 94 | //Check if outputlog and outCSV are the same, we don't want to output log and CSV to same file 95 | if (outputLogFile.stringVal.compare(outputCSVFile.stringVal) == 0) { 96 | std::cerr << "Fatal Error: 'output_csvFile' parameter and 'output_logFile' parameter must be different." << std::endl; 97 | return 0; 98 | } 99 | 100 | //Set up logger 101 | std::Logger logger(outputLogFile.stringVal, outputCSVFile.stringVal, false, parameters.paramList(), inputCSVFile.stringVal); 102 | 103 | logger.log("Parameter: 'output_csvFile' Value: " + outputCSVFile.stringVal); 104 | logger.log("Parameter: 'output_logFile' Value: " + outputLogFile.stringVal); 105 | logger.log("Parameter: 'input_csvFile' Value: " + inputCSVFile.stringVal); 106 | 107 | 108 | std::Param returns = parameters.getParam("returnsInCalculation"); 109 | if(returns.isNull || !returns.isNumber) { 110 | logger.logError("'returnsInCalculation' parameter not found\n", false); 111 | } else { 112 | returnsValue = returns.intVal; 113 | logger.log("Parameter: 'returnsInCalculation' Value: " + std::to_string(returnsValue)); 114 | } 115 | std::Param threshold = parameters.getParam("threshold"); 116 | if(threshold.isNull || !threshold.isNumber) { 117 | logger.logError("'threshold' parameter not found\n", false); 118 | } else { 119 | thresholdValue = threshold.doubleVal; 120 | logger.log("Parameter: 'threshold' Value: " + std::to_string(thresholdValue)); 121 | } 122 | 123 | std::Param startDate = parameters.getParam("startDate"); 124 | std::Param endDate = parameters.getParam("endDate"); 125 | logger.log("Parameter: 'startDate' Value: " + startDate.stringVal); 126 | logger.log("Parameter: 'endDate' Value: " + endDate.stringVal); 127 | 128 | std::MomentumStrategy *momentumStrategy = nullptr; 129 | std::MutantFrogStrategy *mutantFrogStrategy = nullptr; 130 | 131 | if (startDate.isNull || endDate.isNull) { 132 | momentumStrategy = new std::MomentumStrategy(logger, "", "", returnsValue, thresholdValue); 133 | mutantFrogStrategy = new std::MutantFrogStrategy(logger, "", "", thresholdValue); 134 | } else { 135 | momentumStrategy = new std::MomentumStrategy(logger, startDate.stringVal, endDate.stringVal, returnsValue, thresholdValue); 136 | mutantFrogStrategy = new std::MutantFrogStrategy(logger, startDate.stringVal, endDate.stringVal, thresholdValue); 137 | } 138 | std::CSVReader reader(inputCSVFile.stringVal, & foundFile); 139 | if(!foundFile) logger.logError("'input_csvFile' not found\n", true); 140 | 141 | //choose strategy 142 | std::Param strategyParam = parameters.getParam("strategy"); 143 | std::Strategy *strategy = mutantFrogStrategy; //default to mutant frog 144 | if (!strategyParam.isNull && (strategyParam.stringVal.compare("MutantFrog") == 0 145 | || strategyParam.stringVal.compare("MF") == 0)) { 146 | strategy = mutantFrogStrategy; 147 | } else if (!strategyParam.isNull && (strategyParam.stringVal.compare("Momentum") == 0 148 | || strategyParam.stringVal.compare("M") == 0)) { 149 | strategy = momentumStrategy; 150 | } 151 | 152 | run(logger, reader, strategy); 153 | 154 | logger.log("Execution Status: Success!"); 155 | logger.stopLogging(); 156 | 157 | delete momentumStrategy; 158 | delete mutantFrogStrategy; 159 | 160 | return 0; 161 | } 162 | 163 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /src/makefile: -------------------------------------------------------------------------------- 1 | CC=g++ 2 | CFLAGS=-c -std=c++11 3 | O=main.o MomentumStrategy.o Strategy.o TradeDay.o StrategyResult.o Logger.o MomentumStrategyData.o Params.o CSVReader.o UnitTester.o CSVWriter.o MutantFrogStrategy.o TradingInfluences.o 4 | 5 | all: AlgorithmicTrading 6 | 7 | AlgorithmicTrading: $(O) 8 | $(CC) $(O) -o AlgorithmicTrading 9 | 10 | main.o: main.cpp 11 | $(CC) $(CFLAGS) main.cpp 12 | 13 | MomentumStrategy.o: MomentumStrategy.cpp 14 | $(CC) $(CFLAGS) MomentumStrategy.cpp 15 | 16 | Strategy.o: Strategy.cpp 17 | $(CC) $(CFLAGS) Strategy.cpp 18 | 19 | TradeDay.o: TradeDay.cpp 20 | $(CC) $(CFLAGS) TradeDay.cpp 21 | 22 | StrategyResult.o: StrategyResult.cpp 23 | $(CC) $(CFLAGS) StrategyResult.cpp 24 | 25 | Logger.o: Logger.cpp 26 | $(CC) $(CFLAGS) Logger.cpp 27 | 28 | MomentumStrategyData.o: MomentumStrategyData.cpp 29 | $(CC) $(CFLAGS) MomentumStrategyData.cpp 30 | 31 | Params.o: Params.cpp 32 | $(CC) $(CFLAGS) Params.cpp 33 | 34 | CSVReader.o: CSVReader.cpp 35 | $(CC) $(CFLAGS) CSVReader.cpp 36 | 37 | UnitTester.o: UnitTester.cpp 38 | $(CC) $(CFLAGS) UnitTester.cpp 39 | 40 | CSVWriter.o: CSVWriter.cpp 41 | $(CC) $(CFLAGS) CSVWriter.cpp 42 | 43 | CSVWriter.o: CSVWriter.cpp 44 | $(CC) $(CFLAGS) CSVWriter.cpp 45 | 46 | MutantFrogStrategy.o: MutantFrogStrategy.cpp 47 | $(CC) $(CFLAGS) MutantFrogStrategy.cpp 48 | 49 | TradingInfluences.o: TradingInfluences.cpp 50 | $(CC) $(CFLAGS) TradingInfluences.cpp 51 | 52 | clean: 53 | rm *.o AlgorithmicTrading *.log *.csv 54 | -------------------------------------------------------------------------------- /src/makefile_linux: -------------------------------------------------------------------------------- 1 | CC=g++ 2 | CFLAGS=-c -std=c++11 3 | O=-lrt main.o MomentumStrategy.o Strategy.o TradeDay.o StrategyResult.o Logger.o MomentumStrategyData.o Params.o CSVReader.o UnitTester.o CSVWriter.o MutantFrogStrategy.o TradingInfluences.o 4 | 5 | all: AlgorithmicTrading 6 | 7 | AlgorithmicTrading: $(O) 8 | $(CC) $(O) -o AlgorithmicTrading 9 | 10 | main.o: main.cpp 11 | $(CC) $(CFLAGS) main.cpp 12 | 13 | MomentumStrategy.o: MomentumStrategy.cpp 14 | $(CC) $(CFLAGS) MomentumStrategy.cpp 15 | 16 | Strategy.o: Strategy.cpp 17 | $(CC) $(CFLAGS) Strategy.cpp 18 | 19 | TradeDay.o: TradeDay.cpp 20 | $(CC) $(CFLAGS) TradeDay.cpp 21 | 22 | StrategyResult.o: StrategyResult.cpp 23 | $(CC) $(CFLAGS) StrategyResult.cpp 24 | 25 | Logger.o: Logger.cpp 26 | $(CC) $(CFLAGS) Logger.cpp 27 | 28 | MomentumStrategyData.o: MomentumStrategyData.cpp 29 | $(CC) $(CFLAGS) MomentumStrategyData.cpp 30 | 31 | Params.o: Params.cpp 32 | $(CC) $(CFLAGS) Params.cpp 33 | 34 | CSVReader.o: 35 | $(CC) $(CFLAGS) CSVReader.cpp 36 | 37 | UnitTester.o: 38 | $(CC) $(CFLAGS) UnitTester.cpp 39 | 40 | CSVWriter.o: 41 | $(CC) $(CFLAGS) CSVWriter.cpp 42 | 43 | MutantFrogStrategy.o: MutantFrogStrategy.cpp 44 | $(CC) $(CFLAGS) MutantFrogStrategy.cpp 45 | 46 | TradingInfluences.o: TradingInfluences.cpp 47 | $(CC) $(CFLAGS) TradingInfluences.cpp 48 | 49 | clean: 50 | rm *.o AlgorithmicTrading *.log *.csv 51 | -------------------------------------------------------------------------------- /tools/External Tester/tester.py: -------------------------------------------------------------------------------- 1 | # 2 | # TrockAT External Testing Application 3 | # 4 | # This tool is designed to analyse the output from the trockAT algorithmic application 5 | # with an expected output over a serious of tests. It makes use of a random equity trading data 6 | # application to provide its input. 7 | # 8 | # usage: tester.py [module application] [TrockEquityDataGen] 9 | # 10 | # or (if required applications trockAT and TrockEquityDataGen are in current script directory) 11 | # 12 | # usage: teser.py 13 | # 14 | # Additional flags 15 | # 16 | # tester.py --clean #cleans all test files in script directory 17 | # 18 | # Copyright (c) 2015 Trock. All rights reserved. 19 | 20 | #! /usr/bin/python 21 | import csv, re, sys, os, subprocess, datetime, itertools, random 22 | from time import sleep 23 | 24 | def main(argv): 25 | 26 | # Higher variables 27 | curDirectoryPath = os.path.dirname(os.path.abspath(__file__)) + "/"; 28 | modulePath = ""; 29 | trockDataGenPath = ""; 30 | 31 | paramFilePath = curDirectoryPath + "test_ParamFile.param"; 32 | secondParamFilePath = curDirectoryPath + "test_ParamFile2.param"; 33 | testerOrderFile = curDirectoryPath + "test_orders_testerScript.csv" 34 | trockOrderFile = curDirectoryPath + "orders.csv"; 35 | trockLogFile = curDirectoryPath + "test_logfile.txt"; 36 | genPathOutPut = curDirectoryPath + "test_input.csv"; 37 | wosLogFile = curDirectoryPath + "log.txt"; 38 | 39 | #Auto detect required executables () if in current directory 40 | if os.path.isfile(curDirectoryPath + "trockAT.exe"): 41 | modulePath = curDirectoryPath + "trockAT.exe"; 42 | elif os.path.isfile(curDirectoryPath + "trockAT"): 43 | modulePath = curDirectoryPath + "trockAT"; 44 | 45 | if os.path.isfile(curDirectoryPath + "TrockEquityDataGen.exe"): 46 | trockDataGenPath = curDirectoryPath + "TrockEquityDataGen.exe"; 47 | elif os.path.isfile(curDirectoryPath + "TrockEquityDataGen"): 48 | trockDataGenPath = curDirectoryPath + "TrockEquityDataGen"; 49 | 50 | #Add clean command to remove files 51 | if len(sys.argv) == 2 and sys.argv[1] == "--clean": 52 | removemaybe(trockOrderFile); 53 | removemaybe(testerOrderFile); 54 | removemaybe(trockLogFile); 55 | removemaybe(genPathOutPut); 56 | removemaybe(paramFilePath); 57 | removemaybe(secondParamFilePath); 58 | removemaybe(wosLogFile); 59 | sys.exit(1); 60 | 61 | if (not modulePath and not trockDataGenPath): 62 | if len(sys.argv) != 3: 63 | print 'usage:', sys.argv[0], '[module application] [TrockEquityDataGen]'; 64 | sys.exit(1); 65 | else: 66 | modulePath = sys.argv[1]; 67 | trockDataGenPath = sys.argv[2]; 68 | 69 | 70 | testNumber = 30; 71 | 72 | for test in range(1, testNumber + 1): 73 | genNumTrades = random.randint(1,500); 74 | 75 | # Create valid date range by choosing a date between init date and yesterday ( 1 day before now() time) 76 | # Then simply choose a valid start start anytime between this period 77 | initDate = datetime.datetime(1980, 1, 1); 78 | initDateToday = datetime.datetime.now() - datetime.timedelta(days = 1); 79 | dayDifference = (initDateToday - initDate).days; 80 | randOffset = random.randint(0, dayDifference - genNumTrades); #we want our random start date to have enough days for all trades 81 | step = datetime.timedelta(days = randOffset); 82 | genStartDate = initDate + step; 83 | 84 | #Get datetime components 85 | genStartDay = genStartDate.day; 86 | genStartMonth = genStartDate.month; 87 | genStartYear = genStartDate.year; 88 | 89 | #Generate the test input for this round 90 | subprocess.call([trockDataGenPath, str(genNumTrades), str(genStartDay), str(genStartMonth), str(genStartYear), genPathOutPut]) 91 | 92 | #Generate param file to use with TrockAT 93 | startDate = datetime.datetime(genStartYear, genStartMonth, genStartDay); 94 | step = datetime.timedelta(days= genNumTrades - 1); #our end date is exclusive, no trade day generated 95 | endDate = startDate + step; 96 | 97 | #Generate returnsInCalculations and threshold 98 | genReturnsInCalc = random.randint(1, genNumTrades - 1); 99 | genThreshold = random.uniform(0.0, 0.001); 100 | 101 | genParamFile(paramFilePath, secondParamFilePath, genPathOutPut, trockOrderFile, trockLogFile, genReturnsInCalc, genThreshold, startDate, endDate); 102 | 103 | # Call module application to parse input 104 | subprocess.call([modulePath, genPathOutPut, secondParamFilePath, paramFilePath]) 105 | 106 | #Call MSM analyser 107 | MSMAnalyser(genPathOutPut, testerOrderFile, genReturnsInCalc, genThreshold); 108 | 109 | #Print current test num 110 | sys.stdout.write("Test #" + str(test) + ": "); 111 | 112 | #Compare analyser output with module application output 113 | diffNum = diffOrderCSV(testerOrderFile, trockOrderFile); 114 | 115 | #Testing failed, terminate now 116 | if (diffNum > 0): 117 | print "FAILED!"; 118 | print "\t Found in files:", testerOrderFile, trockOrderFile, "\n", "Test number was " + str(test), ", testing", str(genNumTrades), "trade days."; 119 | sys.exit(1); 120 | else: 121 | #Delete files from succesful test 122 | removemaybe(trockOrderFile); 123 | removemaybe(testerOrderFile); 124 | removemaybe(trockLogFile); 125 | removemaybe(genPathOutPut); 126 | removemaybe(paramFilePath); 127 | removemaybe(secondParamFilePath); 128 | removemaybe(wosLogFile); 129 | print "PASSED"; 130 | 131 | sleep(0.5); #small pause to allow applications to read/write files 132 | 133 | #After all tests are passed print out results 134 | print "\nPassed all " + str(testNumber) + " tests successfully."; 135 | 136 | 137 | # Given required parameters, generated a valid paramfile 138 | def genParamFile(outputParamFilePath, outputSecondParamFilePath, inputCSVPath, outputCSVPath, outputLogFilePath, returnsInCalculation, threshold, startDate, endDate): 139 | f = open(outputParamFilePath, 'w'); 140 | 141 | # Generate proper date formats 142 | startDateStr = startDate.strftime('%d-%b-%Y').upper(); 143 | endDateStr = endDate.strftime('%d-%b-%Y').upper(); 144 | 145 | f.write(":input_csvFile:" + inputCSVPath.replace('\\', '/') + "\\\n" + 146 | ":output_csvFile:" + outputCSVPath.replace('\\', '/') + "\\\n" + 147 | ":output_logFile:" + outputLogFilePath.replace('\\', '/') + "\\\n" + 148 | ":returnsInCalculation:" + str(returnsInCalculation) + "\\\n" + 149 | ":threshold:" + str(threshold) + "\\\n" + 150 | ":startDate:" + startDateStr + "\\\n" + 151 | ":startDate:" + endDateStr + "\\\n" 152 | ); 153 | f.close(); 154 | 155 | f2 = open(outputSecondParamFilePath, 'w'); 156 | f2.write("N,TH,DateRange\n" + 157 | str(returnsInCalculation) + "," + str(threshold) + "," + str(startDate.year) + "-" + str(endDate.year) + "\n" 158 | ); 159 | f2.close(); 160 | 161 | # Given an input CSV file, applies MSM to generate the correct, expected output 162 | def MSMAnalyser(inputCSVFile, outputOrderFile, returnsInCalculation, threshhold): 163 | f = open(inputCSVFile, 'rb'); 164 | dataList = list( csv.reader(f, delimiter = ',') ); #convert to scriptable list 165 | dataList.pop(0); #dont need first header row 166 | f.close(); 167 | 168 | #output file stub 169 | f = open(outputOrderFile, 'wb'); 170 | f.write("#Company, Date, Price, Volume, Value, Signal\n"); 171 | 172 | previousPrice = 0.0; 173 | rt = []; 174 | fixedTradeVolume = "100"; 175 | lastMovingAverage = 0; 176 | hadMovingAverage = False; 177 | 178 | Signal = enum(BUY='B', SELL='S', DEFAULT=0); 179 | previousSignal = Signal.DEFAULT; 180 | 181 | #For each trade day 182 | for row in dataList: 183 | tradeCompany = row[0]; 184 | tradeDate = row[1]; 185 | tradeQualifier = row[4]; 186 | lastPrice = row[8]; 187 | tradeVolume = row[9]; 188 | 189 | #Calculate return 190 | if (previousPrice == 0): 191 | if tradeQualifier != "No Trades": 192 | previousPrice = float(lastPrice); 193 | continue; 194 | else: 195 | if tradeQualifier == "No Trades": 196 | continue; 197 | else: 198 | rtVal = (( float(lastPrice) - previousPrice) / previousPrice); 199 | rt.append(rtVal); 200 | previousPrice = float(lastPrice); 201 | 202 | if (len(rt) < returnsInCalculation): 203 | continue; 204 | 205 | #Generate new moving average 206 | movingAverage = 0.0; 207 | 208 | for i in range(len(rt) - returnsInCalculation, len(rt)): 209 | movingAverage += rt[i]; 210 | 211 | movingAverage /= returnsInCalculation; 212 | 213 | if (not hadMovingAverage): 214 | hadMovingAverage = True; 215 | lastMovingAverage = movingAverage; 216 | continue; 217 | 218 | #Get diff between averages 219 | diff = movingAverage - lastMovingAverage; 220 | lastMovingAverage = movingAverage; 221 | 222 | if diff > threshhold: 223 | #Check for double bug signals 224 | if (previousSignal == Signal.BUY): 225 | continue; 226 | 227 | previousSignal = Signal.BUY; 228 | 229 | elif diff < -threshhold: 230 | #Check for double sell signals 231 | if (previousSignal == Signal.SELL): 232 | continue; 233 | 234 | previousSignal = Signal.SELL; 235 | #otherwise ignore signal 236 | else: 237 | continue; 238 | 239 | #generate line to write 240 | orderLine = tradeCompany, tradeDate, regRound(float(lastPrice)), fixedTradeVolume, regRound(float(lastPrice) * float(fixedTradeVolume)), previousSignal + "\n"; 241 | 242 | #write order line 243 | f.write(','.join(orderLine)); 244 | 245 | f.close(); 246 | 247 | #remove if exists 248 | def removemaybe(filename): 249 | try: 250 | os.remove(filename) 251 | except OSError: 252 | pass 253 | 254 | #Compares two CSV files and compares critical values to ensure they are the same 255 | #First parameter should be tester generated CSV file 256 | def diffOrderCSV(first, second): 257 | f1 = open(first, 'rb') 258 | f2 = open(second, 'rb') 259 | reader1 = csv.reader(f1) 260 | reader2 = csv.reader(f2) 261 | 262 | differencesFound = 0; 263 | lineNum = 0; 264 | 265 | # Uses itertools to get array components for each line 266 | for lhs, rhs in itertools.izip(reader1, reader2): 267 | lineNum += 1; 268 | 269 | #Ignore header 270 | if (lineNum == 1): 271 | continue; 272 | 273 | #Compare critical components 274 | diff = False; 275 | 276 | #company name 277 | if lhs[0] != rhs[0]: 278 | diff = True; 279 | 280 | #Check dates 281 | if lhs[1] != rhs[1]: 282 | diff = True; 283 | 284 | #Check prices 285 | lSignal = lhs[5]; 286 | rSignal = rhs[5]; 287 | 288 | if rSignal == "Buy": 289 | rSignal = "B"; 290 | elif rSignal == "Sell": 291 | rSignal = "S"; 292 | 293 | if lSignal != rSignal: 294 | diff = True; 295 | 296 | if diff: 297 | differencesFound += 1; 298 | print "diff #" + str(differencesFound) + ": ", lhs, rhs 299 | 300 | f1.close(); 301 | f2.close(); 302 | 303 | return differencesFound; 304 | 305 | # Round function that behaves in same manner as c++ std::setprecision(2) 306 | def regRound(value): 307 | return "{:.2f}".format(value); 308 | 309 | def enum(**enums): 310 | return type('Enum', (), enums) 311 | 312 | if __name__ == "__main__": 313 | main(sys.argv[1:]) -------------------------------------------------------------------------------- /tools/Mass Data Generator/generator.py: -------------------------------------------------------------------------------- 1 | # 2 | # TrockAT Mass Input Data Test File Generator 3 | # 4 | # This tool is designed to mass generate test files. 5 | # 6 | # usage: generator.py [Gen File Number] [TrockEquityDataGen] 7 | # 8 | # Copyright (c) 2015 Trock. All rights reserved. 9 | 10 | #! /usr/bin/python 11 | import re, sys, os, subprocess, datetime, random 12 | 13 | def main(argv): 14 | 15 | # Higher variables 16 | curDirectoryPath = os.path.dirname(os.path.abspath(__file__)) + "/"; 17 | trockDataGenPath = ""; 18 | testNumber = 0; 19 | 20 | if os.path.isfile(curDirectoryPath + "TrockEquityDataGen.exe"): 21 | trockDataGenPath = curDirectoryPath + "TrockEquityDataGen.exe"; 22 | elif os.path.isfile(curDirectoryPath + "TrockEquityDataGen"): 23 | trockDataGenPath = curDirectoryPath + "TrockEquityDataGen"; 24 | 25 | if (not trockDataGenPath): 26 | if len(sys.argv) != 3: 27 | print 'usage:', sys.argv[0], '[Gen File Number] [TrockEquityDataGen]'; 28 | sys.exit(1); 29 | else: 30 | testNumber = int(sys.argv[1]); 31 | trockDataGenPath = sys.argv[2]; 32 | else: 33 | if len(sys.argv) != 2: 34 | print 'usage:', sys.argv[0], '[Gen File Number] [TrockEquityDataGen]'; 35 | sys.exit(1); 36 | else: 37 | testNumber = int(sys.argv[1]); 38 | 39 | for test in range(1, testNumber + 1): 40 | genNumTrades = random.randint(1,500); 41 | 42 | # Create valid date range by choosing a date between init date and yesterday ( 1 day before now() time) 43 | # Then simply choose a valid start start anytime between this period 44 | initDate = datetime.datetime(1980, 1, 1); 45 | initDateToday = datetime.datetime.now() - datetime.timedelta(days = 1); 46 | dayDifference = (initDateToday - initDate).days; 47 | randOffset = random.randint(0, dayDifference - genNumTrades); #we want our random start date to have enough days for all trades 48 | step = datetime.timedelta(days = randOffset); 49 | genStartDate = initDate + step; 50 | 51 | #Get datetime components 52 | genStartDay = genStartDate.day; 53 | genStartMonth = genStartDate.month; 54 | genStartYear = genStartDate.year; 55 | 56 | outputFile = genStartDate.strftime('%d-%b-%Y').upper() + "_" + str(genNumTrades) + "_" + str(test) + ".csv"; 57 | 58 | #Generate the test input for this round 59 | subprocess.call([trockDataGenPath, str(genNumTrades), str(genStartDay), str(genStartMonth), str(genStartYear), outputFile]) 60 | 61 | 62 | #After all tests are passed print out results 63 | print "\nGenerated " + str(testNumber) + " files successfully."; 64 | 65 | 66 | 67 | if __name__ == "__main__": 68 | main(sys.argv[1:]) -------------------------------------------------------------------------------- /tools/Trock Equity Data Generator/TrockEquityDataGen.c: -------------------------------------------------------------------------------- 1 | // 2 | // TrockEquityDataGen.c 3 | // TrockEquityDataGen 4 | // 5 | // Created by Samuel Whitton on 28/04/2015. 6 | // Copyright (c) 2015 Trock. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #define TRUE 1 14 | #define FALSE 0 15 | #define IS_TRUE(__b) (__b == TRUE) 16 | 17 | #define START_RAND srand((unsigned)time(NULL)) 18 | #define RANDOM_PERCENT ((double)(rand() % 10000) / 9999.0) //granality hack for better pseudo random variances each run 19 | 20 | #define RANDOM_VARIENCE ((RANDOM_PERCENT - 0.5)*2.0) 21 | 22 | #define LOWEST_PRICE 10.0 23 | #define HIGHEST_PRICE 1000.0 24 | #define RANDOM_PRICE_LOW 50.0 25 | #define RANDOM_PRICE_HIGH 499.0 26 | 27 | #define PERCENTAGE_NO_TRADES 0.1 28 | 29 | #define CSV_TITLES "#RIC,Date[L],Time[L],Type,Qualifiers,Open,High,Low,Last,Volume,Open Interest,Settle,Data Source" 30 | #define OPEN_DEFAULT 1.0 31 | #define HIGH_DEFAULT 1.0 32 | #define LOW_DEFAULT 1.0 33 | #define VOLUME_DEFAULT 100000 34 | 35 | #define APPLY_VARIENCE(__value,__max_varience) (__value * ((RANDOM_VARIENCE * __max_varience) + 1.0)) 36 | #define BOUND_PRICE(__price) (__price > HIGHEST_PRICE ? HIGHEST_PRICE : (__price < LOWEST_PRICE ? LOWEST_PRICE : __price)) //within highest and lowest bounds 37 | 38 | //trend definitions 39 | #define SPIKE_CHANCE 0.01 40 | #define SPIKE_MAX_MAGNITUDE 0.5 41 | #define MAX_TREND_VARIENCE 0.5 42 | #define MAX_TREND_MAGNITUDE 0.05 43 | #define TREND_DAYS_MIN 3 44 | #define TREND_DAYS_MAX 20 45 | #define MEDIAN_PRICE_TREND_BIAS_MAGNITUDE 0.3 46 | #define COMPANY_PRODUCTIVITY 0.1 47 | 48 | 49 | typedef int bool; 50 | 51 | typedef struct _date { 52 | int day; 53 | int month; 54 | int year; 55 | } Date; 56 | 57 | 58 | 59 | int daysInMonth(int month, int year) { 60 | month--; //change from 1-12 to 0-11 61 | int numberOfDays; 62 | if (month == 4 || month == 6 || month == 9 || month == 11) { 63 | numberOfDays = 30; 64 | } else if (month == 2) { 65 | bool isLeapYear = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); 66 | if (isLeapYear) 67 | numberOfDays = 29; 68 | else 69 | numberOfDays = 28; 70 | } else { 71 | numberOfDays = 31; 72 | } 73 | return numberOfDays; 74 | } 75 | 76 | Date addDays(Date date, int days) { 77 | //hopefull we are not adding many days... 78 | for (int i = 0; i != days; ++i) { 79 | date.day++; 80 | if (date.day > daysInMonth(date.month, date.year)) { 81 | date.day = 1; 82 | date.month++; 83 | if (date.month > 12) { 84 | date.month = 1; 85 | date.year++; 86 | } 87 | } 88 | } 89 | return date; 90 | } 91 | 92 | 93 | 94 | int main(int argc, const char * argv[]) { 95 | // insert code here... 96 | //printf("Hello, World!\n"); 97 | 98 | char *months[13] = {"","JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"}; 99 | 100 | bool hasFileOut = FALSE; 101 | FILE *file = stdout; //default 102 | 103 | if (argc == 6) { 104 | file = fopen(argv[5], "w"); 105 | hasFileOut = TRUE; 106 | 107 | if (file == NULL) { 108 | printf("Can't open output file: %s\n", argv[5]); 109 | return 1; 110 | } 111 | 112 | } else if (argc != 5) { 113 | 114 | printf("usage: %s [num trades] [starting day] [starting month] [starting year] [optional output file]\n", argv[0]); 115 | return 1; 116 | } 117 | 118 | 119 | Date currDate; 120 | currDate.day = atoi(argv[2]); 121 | currDate.month = atoi(argv[3]); 122 | currDate.year = atoi(argv[4]); 123 | 124 | if (currDate.day < 1 || currDate.month < 1 125 | || currDate.year < 1 || currDate.month > 12) { 126 | printf("Incorrect date: %s %s %s\n", argv[2], argv[3], argv[4]); 127 | return 1; 128 | } 129 | 130 | 131 | fprintf(file, CSV_TITLES "\n"); 132 | 133 | START_RAND; 134 | 135 | double firstPrice = RANDOM_PERCENT * (RANDOM_PRICE_HIGH - RANDOM_PRICE_LOW) 136 | + RANDOM_PRICE_LOW; //core of trend bias so we dont have a fatalistic model (all companies must die) 137 | 138 | int currentTrendDaysLeft = 0; 139 | double currentTrend = 0; 140 | double lastPrice = firstPrice; 141 | 142 | int numDays = atoi(argv[1]); 143 | for (int i = 0; i < numDays; ++i) { 144 | 145 | if (RANDOM_PERCENT < PERCENTAGE_NO_TRADES) { 146 | fprintf(file, "MEMPHISC,%d-%s-%d,,End Of Day,No Trades,,,,,,,,Verified\n", currDate.day, months[currDate.month], currDate.year); 147 | } else { 148 | 149 | //calculate next price 150 | 151 | double thisPrice = lastPrice; 152 | 153 | if (RANDOM_PERCENT < SPIKE_CHANCE) { 154 | //spike happened! 155 | thisPrice = APPLY_VARIENCE(lastPrice, SPIKE_MAX_MAGNITUDE); 156 | 157 | } else { 158 | if (currentTrendDaysLeft <= 0) { 159 | //new trend 160 | double trendBias = -(lastPrice / firstPrice - 1.0) * MEDIAN_PRICE_TREND_BIAS_MAGNITUDE; 161 | if (trendBias < COMPANY_PRODUCTIVITY) 162 | trendBias = COMPANY_PRODUCTIVITY; //dont accelerate death! 163 | 164 | //printf("Bias: %lf\n", trendBias); 165 | 166 | currentTrendDaysLeft = TREND_DAYS_MIN + (TREND_DAYS_MAX - TREND_DAYS_MIN) * RANDOM_PERCENT; 167 | currentTrend = MAX_TREND_MAGNITUDE * RANDOM_VARIENCE + trendBias; 168 | } 169 | //continue trend 170 | currentTrendDaysLeft--; 171 | thisPrice = (APPLY_VARIENCE(lastPrice, APPLY_VARIENCE(currentTrend, MAX_TREND_VARIENCE))); 172 | } 173 | 174 | thisPrice = BOUND_PRICE(thisPrice); 175 | 176 | //default static stuff (that looks kinda plausible) 177 | double priceOpen = APPLY_VARIENCE(thisPrice, 0.05); 178 | double priceHigh = thisPrice * 1.07; 179 | double priceLow = thisPrice * 0.93; 180 | 181 | fprintf(file, "MEMPHISC,%d-%s-%d,,End Of Day,,%.2lf,%.2lf,%.2lf,%.2lf,%d,,,Verified\n", currDate.day, months[currDate.month], currDate.year, priceOpen, priceHigh, priceLow, thisPrice, VOLUME_DEFAULT); 182 | 183 | lastPrice = thisPrice; 184 | } 185 | 186 | currDate = addDays(currDate, 1); 187 | } 188 | 189 | 190 | if (IS_TRUE(hasFileOut)) { 191 | fclose(file); 192 | } 193 | 194 | return 0; 195 | } 196 | 197 | 198 | 199 | --------------------------------------------------------------------------------