├── src ├── readme.md ├── config.cfg ├── Backtester.cpp ├── DataWarehouse.cpp ├── SignalGenerator.cpp ├── constants.h ├── gamma.hpp ├── typedefs.h ├── configuration.hpp ├── main.cpp ├── SignalGenerator.hpp ├── gamma.cpp ├── MathUtility.h ├── configuration.cpp ├── Options.cpp ├── Backtester.hpp ├── DataWarehouse.hpp ├── PortfolioEngine.hpp ├── Options.hpp └── PortfolioEngine.cpp ├── README.md └── data └── pgsql_command.sql /src/readme.md: -------------------------------------------------------------------------------- 1 | This folder contains source code. 2 | -------------------------------------------------------------------------------- /src/config.cfg: -------------------------------------------------------------------------------- 1 | strategyName=GammaScalping 2 | movingWindow=20 3 | entryVol=0.15 4 | exitVol=0.25 -------------------------------------------------------------------------------- /src/Backtester.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Backtester.cpp 3 | // pgsql 4 | // 5 | // Created by FuYongrui on 5/1/16. 6 | // Copyright © 2016 FuYongrui. All rights reserved. 7 | // 8 | 9 | #include "Backtester.hpp" 10 | -------------------------------------------------------------------------------- /src/DataWarehouse.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // DataWarehouse.cpp 3 | // pgsql 4 | // 5 | // Created by FuYongrui on 5/1/16. 6 | // Copyright © 2016 FuYongrui. All rights reserved. 7 | // 8 | 9 | #include "DataWarehouse.hpp" 10 | -------------------------------------------------------------------------------- /src/SignalGenerator.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // SignalGenerator.cpp 3 | // pgsql 4 | // 5 | // Created by FuYongrui on 5/1/16. 6 | // Copyright © 2016 FuYongrui. All rights reserved. 7 | // 8 | 9 | #include "SignalGenerator.hpp" 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GammaScalping 2 | This is a volatility trading strategy. Buying the straddle when implied vol is subsided, at the hope that it will spike in the near future. At the same time, we delta hedge our portfolio to remove the affect of underlying movement on portfolio. 3 | 4 | You will need PostgreSQL C++ library libpqxx and QuantLib to compile. You will also need include Boost library header file on search path, and link libboost_filesystem.a and libboost_system.a. 5 | -------------------------------------------------------------------------------- /src/constants.h: -------------------------------------------------------------------------------- 1 | // 2 | // constants.h 3 | // pgsql 4 | // 5 | // Created by FuYongrui on 5/6/16. 6 | // Copyright © 2016 FuYongrui. All rights reserved. 7 | // 8 | 9 | #ifndef constants_h 10 | #define constants_h 11 | 12 | #include 13 | 14 | 15 | static const string STRAT_NAME = "strategyName"; 16 | static const string MOVING_WINDOW = "movingWindow"; 17 | static const string ENTRY_VOL = "entryVol"; 18 | static const string EXIT_VOL = "exitVol"; 19 | 20 | 21 | #endif /* constants_h */ 22 | -------------------------------------------------------------------------------- /data/pgsql_command.sql: -------------------------------------------------------------------------------- 1 | drop table if exists spyoptions; 2 | 3 | create table spyoptions 4 | ( 5 | cur_date date not null, 6 | ex_date date not null, 7 | flag char(1) not null, 8 | k numeric(12,5) not null, 9 | bid numeric(12,5) not null, 10 | offer numeric(12,5) not null, 11 | price numeric(12,5), 12 | primary key (cur_date, ex_date, flag, k) 13 | ); 14 | 15 | copy spyoptions (cur_date, ex_date, flag, k, bid, offer) 16 | from '/Users/alanfu/Documents/Codes/cpp/GammaScalping/data/op_SPY.csv' 17 | delimiter ',' csv header; 18 | 19 | -------------------------------------------------------------------------------- /src/gamma.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // gamma.hpp 3 | // pgsql 4 | // 5 | // Created by FuYongrui on 5/1/16. 6 | // Copyright © 2016 FuYongrui. All rights reserved. 7 | // 8 | 9 | #ifndef gamma_hpp 10 | #define gamma_hpp 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | using namespace std; 21 | 22 | typedef boost::shared_ptr Conn_Ptr; 23 | 24 | void make_conn(); 25 | 26 | 27 | #endif /* gamma_hpp */ 28 | -------------------------------------------------------------------------------- /src/typedefs.h: -------------------------------------------------------------------------------- 1 | // 2 | // typedefs.h 3 | // pgsql 4 | // 5 | // Created by FuYongrui on 5/6/16. 6 | // Copyright © 2016 FuYongrui. All rights reserved. 7 | // 8 | 9 | #ifndef typedefs_h 10 | #define typedefs_h 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | using namespace std; 17 | 18 | static const boost::char_separator sep("#;,="); 19 | typedef vector> TwoDStringVector; 20 | typedef multimap StringToStringMap; 21 | typedef boost::tokenizer> Tokenizer; 22 | typedef StringToStringMap::const_iterator MapIter; 23 | 24 | 25 | #endif /* typedefs_h */ 26 | -------------------------------------------------------------------------------- /src/configuration.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // configuration.hpp 3 | // pgsql 4 | // 5 | // Created by FuYongrui on 5/6/16. 6 | // Copyright © 2016 FuYongrui. All rights reserved. 7 | // 8 | 9 | #ifndef configuration_hpp 10 | #define configuration_hpp 11 | 12 | #include 13 | 14 | #include "typedefs.h" 15 | #include 16 | #include 17 | #include 18 | #include "constants.h" 19 | 20 | using namespace std; 21 | 22 | 23 | 24 | struct AppConfig 25 | { 26 | private: 27 | //=========== configuration parameters ==========// 28 | 29 | string strategyName; 30 | int movingWindow; 31 | double entryVol; 32 | double exitVol; 33 | 34 | public: 35 | void setConfigParams(const StringToStringMap& configMap); 36 | 37 | void createAppConfig(const string& fileName); 38 | 39 | StringToStringMap readConfigFile(const string& fileName); 40 | 41 | const string& getStratName() const 42 | { 43 | return strategyName; 44 | } 45 | 46 | private: 47 | 48 | //=========== utility functions ==========// 49 | 50 | TwoDStringVector parse(const string fileName); 51 | 52 | inline vector parseLine(const string& line); 53 | }; 54 | 55 | #endif /* configuration_hpp */ 56 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // main.cpp 3 | // pgsql 4 | // 5 | // Created by FuYongrui on 12/10/15. 6 | // Copyright © 2015 FuYongrui. All rights reserved. 7 | // 8 | 9 | #include 10 | 11 | #include "gamma.hpp" 12 | #include "DataWarehouse.hpp" 13 | #include "Options.hpp" 14 | #include "SignalGenerator.hpp" 15 | #include "Backtester.hpp" 16 | #include "configuration.hpp" 17 | #include 18 | 19 | using namespace std; 20 | 21 | int main(int argc, const char * argv[]) { 22 | 23 | boost::filesystem::path cd(__FILE__); 24 | 25 | cd.remove_leaf(); 26 | const string filename = cd.string() + "/config.cfg"; 27 | AppConfig config; 28 | 29 | config.createAppConfig(filename); 30 | auto StockData_ptr = boost::make_shared(); 31 | auto OptionData_ptr = boost::make_shared(); 32 | 33 | GammaScalping::Volatility entry_signal = 0.2; 34 | GammaScalping::Volatility exit_signal = 0.3; 35 | 36 | GammaScalping::Backtester my_backtest(OptionData_ptr, 37 | StockData_ptr, 38 | entry_signal, 39 | exit_signal); 40 | 41 | my_backtest.start_backtest(); 42 | 43 | //make_conn(); 44 | 45 | 46 | } 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/SignalGenerator.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // SignalGenerator.hpp 3 | // pgsql 4 | // 5 | // Created by FuYongrui on 5/1/16. 6 | // Copyright © 2016 FuYongrui. All rights reserved. 7 | // 8 | 9 | #ifndef SignalGenerator_hpp 10 | #define SignalGenerator_hpp 11 | 12 | #include 13 | 14 | #include "DataWarehouse.hpp" 15 | #include "Options.hpp" 16 | #include 17 | //#include 18 | #include 19 | 20 | namespace GammaScalping 21 | { 22 | enum Signal {ENTER,KEEP,EXIT};//Signals 23 | 24 | class SignalGenerator 25 | { 26 | public: 27 | 28 | SignalGenerator(Volatility entry = 0.2, Volatility exit = 0.3) 29 | { 30 | entry_vol = entry; 31 | exit_vol = exit; 32 | } 33 | 34 | Signal generate_signal() 35 | { 36 | Signal signal = Signal::KEEP; 37 | 38 | //=========== please use your own trading idea :) ==========// 39 | 40 | return signal; 41 | } 42 | 43 | void update_option(Option_Sptr option_call, Option_Sptr option_put) 44 | { 45 | CallOption = option_call; 46 | PutOption = option_put; 47 | } 48 | 49 | private: 50 | list vol_queue; 51 | int window_size = 20; 52 | Volatility entry_vol; 53 | Volatility exit_vol; 54 | Option_Sptr CallOption; 55 | Option_Sptr PutOption; 56 | }; 57 | } 58 | #endif /* SignalGenerator_hpp */ 59 | -------------------------------------------------------------------------------- /src/gamma.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // gamma.cpp 3 | // pgsql 4 | // 5 | // Created by FuYongrui on 5/1/16. 6 | // Copyright © 2016 FuYongrui. All rights reserved. 7 | // 8 | 9 | #include "gamma.hpp" 10 | using namespace std; 11 | 12 | string stocktable="SPYSTOCKS"; 13 | string optiontable="SPYOPTIONS"; 14 | string recordtable="RECORDS"; 15 | 16 | void make_conn() 17 | { 18 | Conn_Ptr conn; 19 | try{ 20 | conn = boost::make_shared("dbname=mydb user=alanfu hostaddr=127.0.0.1 port=5432"); 21 | 22 | if (conn->is_open()) { 23 | cout << "Opened database successfully: " << conn->dbname() << endl; 24 | } else { 25 | throw runtime_error("Cannot connect to database!"); 26 | } 27 | 28 | pqxx::work W(*conn); 29 | 30 | string temp = "SELECT * FROM "+stocktable+";"; 31 | const char* sql=temp.c_str(); 32 | 33 | pqxx::result R = W.exec(sql); 34 | 35 | pqxx::result::const_iterator iter=R.begin(); 36 | 37 | for(auto tup : R) 38 | { 39 | cout << tup[1].as() << endl; 40 | cout << stoi(tup[0].as().substr(5,2)) + 1 << endl; 41 | } 42 | 43 | string cur_date = "2011-01-03"; 44 | string ex_date = "2011-01-07"; 45 | string callput = "C"; 46 | temp = "select price from " + optiontable + " where cur_date = date \'" + cur_date + "\' and ex_date = date \'" + ex_date + "\' and flag = \'" + callput + "\' and k = 113;"; 47 | sql=temp.c_str(); 48 | 49 | R = W.exec(sql); 50 | cout << stof(R.begin()[0].as()) + 1 << endl; 51 | W.commit(); 52 | conn->disconnect (); 53 | 54 | }catch (runtime_error &e){ 55 | cerr << e.what() << std::endl; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/MathUtility.h: -------------------------------------------------------------------------------- 1 | // 2 | // MathUtility.h 3 | // pgsql 4 | // 5 | // Created by FuYongrui on 5/1/16. 6 | // Copyright © 2016 FuYongrui. All rights reserved. 7 | // 8 | 9 | #ifndef MathUtility_h 10 | #define MathUtility_h 11 | 12 | namespace GammaScalping 13 | { 14 | inline double R(const double z) 15 | { 16 | const std::vector 17 | a = { 0.319381530 , -0.356563782 , 1.781477937 , -1.821255978 , 1.330274429 }; 18 | 19 | return z*(z*(z*(z*( a.at(4)*z+a.at(3) ) + a.at(2) ) + a.at(1) ) + a.at(0)); 20 | } 21 | 22 | inline double 23 | normal_cdf (const double x){ 24 | if ( x > 0 ){ 25 | double result = 0.0 ; 26 | result = 1.0 - 1.0/sqrt(2.0*M_PI)*exp(-x*x/2.0)*R(1.0/(1.0 + 0.2316419*x)); 27 | return result; 28 | } 29 | else{ 30 | return 1.0-normal_cdf(-x) ; 31 | } 32 | } 33 | 34 | inline double 35 | normal_pdf (const double x){ 36 | return (1.0/sqrt(2.0*M_PI)*exp(-x*x/2.0)); 37 | } 38 | 39 | template 40 | double root_newton(T &func, const double x1 = 0.0, const double x2 = 2.0, const double acc = 0.00001) { 41 | // input a functor & range( x1 , x2 ) in which you believe there is a root & accuracy level 42 | // the functor provided must have a dff() method 43 | 44 | const int MAX_NUM_TRIAL = 50000 ; 45 | double rtn = 0.5 * ( x1 + x2 ) ; 46 | 47 | for ( size_t i = 0 ; i < MAX_NUM_TRIAL ; ++i ){ 48 | 49 | double f = func( rtn ); 50 | double df = func.diff( rtn ); 51 | double dx = f/df; 52 | 53 | rtn -= dx; 54 | if ( (x1-rtn) * (rtn-x2) < 0.0 ) 55 | 56 | throw std::runtime_error 57 | (" Jumped out of brackets in root_newton method, check your range! "); 58 | 59 | if ( fabs(dx) < acc ) 60 | return rtn; 61 | 62 | } 63 | 64 | throw std::runtime_error 65 | (" Maximum number of iterations exceeded in rtnewt, may caused by accuracy level "); 66 | 67 | } 68 | } 69 | 70 | #endif /* MathUtility_h */ 71 | -------------------------------------------------------------------------------- /src/configuration.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // configuration.cpp 3 | // pgsql 4 | // 5 | // Created by FuYongrui on 5/6/16. 6 | // Copyright © 2016 FuYongrui. All rights reserved. 7 | // 8 | 9 | #include "configuration.hpp" 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | void AppConfig::setConfigParams(const StringToStringMap& configMap) 16 | { 17 | MapIter e = configMap.end(); 18 | MapIter it; 19 | 20 | it = configMap.find(STRAT_NAME); 21 | if (it != e) 22 | strategyName = static_cast(it->second); 23 | else 24 | cerr << "Failed to config strategy name." << endl; 25 | 26 | it = configMap.find(MOVING_WINDOW); 27 | if (it != e) 28 | movingWindow = boost::lexical_cast(it->second); 29 | else 30 | cerr << "Failed to config moving window." << endl; 31 | 32 | it = configMap.find(ENTRY_VOL); 33 | if (it != e) 34 | entryVol = boost::lexical_cast(it->second); 35 | else 36 | cerr << "Failed to config entry vol." << endl; 37 | 38 | it = configMap.find(EXIT_VOL); 39 | if (it != e) 40 | exitVol = boost::lexical_cast(it->second); 41 | else 42 | cerr << "Failed to config exit vol." << endl; 43 | } 44 | 45 | void AppConfig::createAppConfig(const string& fileName) 46 | { 47 | auto a = readConfigFile(fileName); 48 | setConfigParams(a); 49 | } 50 | 51 | StringToStringMap AppConfig::readConfigFile(const string& fileName) 52 | { 53 | TwoDStringVector cfgFileData = parse(fileName); 54 | 55 | vector row; 56 | StringToStringMap ret; 57 | 58 | for (auto it = cfgFileData.begin(); it != cfgFileData.end(); it++) 59 | { 60 | row = *it; 61 | string key = row[0]; 62 | string val = row[1]; 63 | 64 | if (key[0] == '#' || key.empty()) 65 | continue; 66 | 67 | ret.insert(pair(key, val)); 68 | } 69 | 70 | 71 | return ret; 72 | } 73 | 74 | 75 | TwoDStringVector AppConfig::parse(const string fileName) 76 | { 77 | ifstream file(fileName.c_str()); 78 | 79 | TwoDStringVector ret; 80 | string line; 81 | ret.clear(); 82 | 83 | if (file.is_open()) 84 | while (file.good()) 85 | { 86 | getline(file, line); 87 | ret.push_back(parseLine(line)); 88 | } 89 | 90 | return ret; 91 | } 92 | 93 | vector AppConfig::parseLine(const string& line) 94 | { 95 | Tokenizer token(line, sep); 96 | vector tokens; 97 | tokens.clear(); 98 | 99 | for (auto it = token.begin(); it != token.end(); it++) 100 | { 101 | tokens.push_back(*it); 102 | } 103 | return tokens; 104 | } 105 | 106 | -------------------------------------------------------------------------------- /src/Options.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Options.cpp 3 | // pgsql 4 | // 5 | // Created by FuYongrui on 5/1/16. 6 | // Copyright © 2016 FuYongrui. All rights reserved. 7 | // 8 | 9 | #include "Options.hpp" 10 | 11 | namespace GammaScalping 12 | { 13 | 14 | PriceType BS_CALL_PRICE(const PriceType stock_price, 15 | const PriceType strike, 16 | const RateType rate, 17 | const Volatility vol, 18 | const YearFraction time_to_maturity) 19 | { 20 | double d1 = ( log(stock_price/strike) + (rate + 0.5*vol*vol)*time_to_maturity ) / ( vol*sqrt(time_to_maturity) ) ; 21 | double d2 = ( log(stock_price/strike) + (rate - 0.5*vol*vol)*time_to_maturity ) / ( vol*sqrt(time_to_maturity) ) ; 22 | return ( stock_price*normal_cdf(d1) - strike*exp(-rate*time_to_maturity)*normal_cdf(d2) ); 23 | } 24 | 25 | PriceType BS_PUT_PRICE(const PriceType stock_price, 26 | const PriceType strike, 27 | const RateType rate, 28 | const Volatility vol, 29 | const YearFraction time_to_maturity) 30 | { 31 | double d1 = ( log(stock_price/strike) + (rate + 0.5*vol*vol)*time_to_maturity ) / ( vol*sqrt(time_to_maturity) ) ; 32 | double d2 = ( log(stock_price/strike) + (rate - 0.5*vol*vol)*time_to_maturity ) / ( vol*sqrt(time_to_maturity) ) ; 33 | return ( -stock_price*normal_cdf(-d1) + strike*exp(-rate*time_to_maturity)*normal_cdf(-d2) ); 34 | } 35 | 36 | Volatility BS_VEGA(const PriceType stock_price, 37 | const PriceType strike, 38 | const RateType rate, 39 | const Volatility vol, 40 | const YearFraction time_to_maturity) 41 | { 42 | double d1 = ( log(stock_price/strike) + (rate + 0.5*vol*vol)*time_to_maturity ) / ( vol*sqrt(time_to_maturity) ) ; 43 | return stock_price * sqrt(time_to_maturity) * normal_pdf(d1); 44 | } 45 | 46 | void Find_Root_Helper::set_params(const PriceType _stock_price, 47 | const StrikeType _strike, 48 | const YearFraction _time_to_maturity, 49 | const CallPut _call_put, 50 | const PriceType _option_price) 51 | { 52 | stock_price = _stock_price; 53 | strike = _strike; 54 | time_to_maturity = _time_to_maturity; 55 | call_put = _call_put; 56 | option_price = _option_price; 57 | } 58 | 59 | Volatility Find_Root_Helper::operator()(Volatility vol) 60 | { 61 | if (call_put == CallPut::CALL) 62 | return BS_CALL_PRICE(stock_price, 63 | strike, 64 | rate, 65 | vol, 66 | time_to_maturity) - option_price; 67 | else 68 | return BS_PUT_PRICE(stock_price, 69 | strike, 70 | rate, 71 | vol, 72 | time_to_maturity) - option_price; 73 | } 74 | 75 | Volatility Find_Root_Helper::diff(Volatility vol) 76 | { 77 | return BS_VEGA(stock_price, 78 | strike, 79 | rate, 80 | vol, 81 | time_to_maturity); 82 | } 83 | 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/Backtester.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Backtester.hpp 3 | // pgsql 4 | // 5 | // Created by FuYongrui on 5/1/16. 6 | // Copyright © 2016 FuYongrui. All rights reserved. 7 | // 8 | 9 | #ifndef Backtester_hpp 10 | #define Backtester_hpp 11 | 12 | #include 13 | 14 | #include "DataWarehouse.hpp" 15 | #include "Options.hpp" 16 | #include "SignalGenerator.hpp" 17 | //#include "PortfolioEngine.hpp" 18 | 19 | 20 | namespace GammaScalping 21 | { 22 | 23 | 24 | class Backtester 25 | { 26 | public: 27 | Backtester(OptionDataWarehouse_Sptr op_data_ptr, StockDataWarehouse_Sptr stk_data_ptr, Volatility entry, Volatility exit) : 28 | OptionData_ptr(op_data_ptr), 29 | StockData_ptr(stk_data_ptr), 30 | Signal_Generator(entry, exit)/*, 31 | Portfolio_Engine(PortfolioEngine(op_data_ptr))*/ 32 | { 33 | StockPriceTimeSeries = StockData_ptr->make_query(); 34 | } 35 | 36 | void start_backtest() 37 | { 38 | for(auto tup : StockPriceTimeSeries) 39 | { 40 | auto current_date = tup[0].as(); 41 | auto stock_price = tup[1].as(); 42 | auto expiry_date = get_expiry(current_date); 43 | auto strike = get_strike(stock_price); 44 | cout << current_date << ' ' << stock_price << ' ' << expiry_date << ' ' << strike << endl; 45 | 46 | auto CallOption = boost::make_shared