├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── filters.output └── ValueCases-5YMA-20180618.xlsx ├── lib-jri ├── JRI.jar ├── JRIEngine.jar ├── REngine.jar ├── rtest.java └── rtest2.java ├── lib-rserve ├── REngine.jar └── RserveEngine.jar ├── lib ├── cube-sdk-ext-1.0-SNAPSHOT.jar └── taobao-express-3.0.18.jar ├── mybatis-generator-core-1.3.2 ├── generate.bat ├── generate.sh ├── generatorConfig-MySQL.xml ├── generatorConfig-pg.xml ├── mybatis-generator-core-1.3.2.jar ├── mysql-connector-java-5.1.35.jar └── postgresql-9.4.1208.jar ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── diffwind │ │ ├── constants │ │ ├── DataSource.java │ │ └── Index.java │ │ ├── dao │ │ ├── mapper │ │ │ ├── CreateIndexMapper.java │ │ │ ├── EastmoneyStockBbsjMapper.java │ │ │ ├── EastmoneyStockRzrqJsonMapper.java │ │ │ ├── QueryMapper.java │ │ │ ├── SinaStockMapper.java │ │ │ ├── SinaZjhhangyeMapper.java │ │ │ ├── SinaZjhhangyeStockMapper.java │ │ │ ├── TdxStockDayMapper.java │ │ │ ├── TruncateTableMapper.java │ │ │ ├── XueqiuStockFinanceMapper.java │ │ │ ├── XueqiuStockMapper.java │ │ │ └── XueqiuStockShareschgMapper.java │ │ ├── mapping │ │ │ ├── CreateIndexMapper.xml │ │ │ ├── EastmoneyStockBbsjMapper.xml │ │ │ ├── EastmoneyStockRzrqJsonMapper.xml │ │ │ ├── QueryMapper.xml │ │ │ ├── SinaStockMapper.xml │ │ │ ├── SinaZjhhangyeMapper.xml │ │ │ ├── SinaZjhhangyeStockMapper.xml │ │ │ ├── TdxStockDayMapper.xml │ │ │ ├── TruncateTableMapper.xml │ │ │ ├── XueqiuStockFinanceMapper.xml │ │ │ ├── XueqiuStockMapper.xml │ │ │ └── XueqiuStockShareschgMapper.xml │ │ ├── model │ │ │ ├── EastmoneyStockBbsj.java │ │ │ ├── EastmoneyStockRzrqJson.java │ │ │ ├── SinaStock.java │ │ │ ├── SinaZjhhangye.java │ │ │ ├── SinaZjhhangyeStock.java │ │ │ ├── TdxStockDay.java │ │ │ ├── XueqiuStock.java │ │ │ ├── XueqiuStockFinance.java │ │ │ └── XueqiuStockShareschg.java │ │ └── util │ │ │ └── TableUtil.java │ │ ├── data │ │ ├── EastmoneyStockRzrq.java │ │ ├── SinaHangyeDataRobot.java │ │ ├── SinaHqDataRobot.java │ │ ├── SinaStockCorpInfoDataRobot.java │ │ ├── TdxDataDecoder.java │ │ ├── XueqiuHqDataRobot.java │ │ ├── XueqiuStockFinanceDataRobot.java │ │ ├── XueqiuStockFinancialStatementRobot.java │ │ └── XueqiuStockShareschgDataRobot.java │ │ ├── expr │ │ ├── ExpressRunnerFactory.java │ │ ├── function │ │ │ ├── MAFunction.java │ │ │ ├── MAXFunction.java │ │ │ ├── MEANFunction.java │ │ │ ├── MINFunction.java │ │ │ ├── RANGEFunction.java │ │ │ ├── SUMFunction.java │ │ │ └── WHICHFunction.java │ │ └── operator │ │ │ ├── AnyGTEOperator.java │ │ │ ├── AnyGTOperator.java │ │ │ ├── AnyLTEOperator.java │ │ │ ├── AnyLTOperator.java │ │ │ ├── EachGTEOperator.java │ │ │ ├── EachGTOperator.java │ │ │ ├── EachLTEOperator.java │ │ │ ├── EachLTOperator.java │ │ │ ├── GTEOperator.java │ │ │ ├── GTOperator.java │ │ │ ├── LTEOperator.java │ │ │ └── LTOperator.java │ │ ├── main │ │ ├── DiffWindFirstTime.java │ │ └── DiffWindMain.java │ │ ├── stats │ │ ├── DataHandler.java │ │ ├── JRIchart │ │ │ └── TimeSeriesChart.java │ │ ├── MemStatsStockDay.java │ │ ├── MemStatsStockQuarter.java │ │ ├── R │ │ │ ├── .Rapp.history │ │ │ ├── LongWindCasesAnalysis.R │ │ │ ├── PGconn.R │ │ │ └── StkFinance.R │ │ ├── StockDayView.java │ │ ├── StockDayViewWind.java │ │ ├── StockQuarterView.java │ │ ├── StockQuarterViewWind.java │ │ ├── filters │ │ │ ├── FilterRules.java │ │ │ └── MingxingCasesFilter.java │ │ └── stats.sql │ │ └── util │ │ ├── Algorithm.java │ │ ├── DateUtil.java │ │ ├── DoubleCheck.java │ │ ├── ExcelUtil.java │ │ ├── Functions.java │ │ ├── HttpUtil.java │ │ ├── PGCopy.java │ │ ├── RiskProb.java │ │ └── ThreadPoolExecutorManager.java ├── resources │ ├── config.properties │ ├── jdbc.properties │ ├── log4j.properties │ ├── log4j2.xml │ └── mybatis-config.xml └── sqlscripts │ ├── DBscripts │ ├── eastmoney_tables.sql │ ├── index.sql │ ├── query.sql │ ├── sina_tables.sql │ ├── tdx_tables.sql │ └── xueqiu_tables.sql └── test └── java ├── com └── diffwind │ ├── dao │ ├── QueryMapperTest.java │ └── TruncateTableMapperTest.java │ ├── data │ └── EastmoneyStockRzrqJsonTest.java │ ├── stats │ ├── JRIChartTest.java │ ├── MemStatsStockDayTest.java │ └── MemStatsStockQuarterTest.java │ └── util │ ├── CalendarTest.java │ ├── FunctionsTest.java │ ├── GregorianCalendarTest.java │ └── StringUtilTest.java ├── qlexpress └── extend │ └── OperatorTest.java └── sort └── CollectionTest.java /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse project files 2 | .project 3 | .classpath 4 | .settings 5 | 6 | # IntelliJ IDEA project files and directories 7 | *.iml 8 | *.ipr 9 | *.iws 10 | .idea/ 11 | 12 | # Geany project file 13 | .geany 14 | 15 | # KDevelop project file and directory 16 | .kdev4/ 17 | *.kdev4 18 | 19 | # Build targets 20 | /target 21 | */target 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## DiffWind是什么 2 | DiffWind是一个量化投资系统,主要包括基于指标的筛选模型(案例学习部分因为不成熟并没有开源)。 3 | 4 | ## DiffWind如何使用 5 | DiffWind使用的数据源: 6 | **网易:** 7 | 财务报表历史数据 8 | 日线交易数据 9 | 10 | **东方财富:** 11 | 资金流、沪深股通资金流数据 12 | 融资融券历史数据 13 | 大宗交易数据 14 | 其他特色数据 15 | 16 | **新浪:** 17 | 行业分类数据 18 | 分红配股数据(用于复权计算) 19 | 20 | **同花顺:** 21 | 分红、财务数据等 22 | 23 | **雪球(因发爬虫问题已弃用):** 24 | 财务报表历史数据 25 | 股本结构历史数据 26 | 27 | 28 | **使用步骤:** 29 | 1. 安装数据库:PostgreSQL 9.x以上 30 | 2. 执行src/main/sqlscripts下的SQL脚本文件,创建表和索引 31 | 3. DiffWind初次执行时需准备历史数据,初始化数据库(只需执行一次,以后不需要再执行): 32 | DiffWindFirstTime 33 | 4. 执行筛选模型: 34 | DiffWindMain 35 | 36 | 37 | ## 感谢 38 | 右上角请帮忙点星(Star) 39 | 欢迎推荐给志同道合的朋友,大家共同交流,一起进步 40 | -------------------------------------------------------------------------------- /filters.output/ValueCases-5YMA-20180618.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billberg/DiffWind/4f9afe56e7371e24cfa489f11e8869cc3789f5cf/filters.output/ValueCases-5YMA-20180618.xlsx -------------------------------------------------------------------------------- /lib-jri/JRI.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billberg/DiffWind/4f9afe56e7371e24cfa489f11e8869cc3789f5cf/lib-jri/JRI.jar -------------------------------------------------------------------------------- /lib-jri/JRIEngine.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billberg/DiffWind/4f9afe56e7371e24cfa489f11e8869cc3789f5cf/lib-jri/JRIEngine.jar -------------------------------------------------------------------------------- /lib-jri/REngine.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billberg/DiffWind/4f9afe56e7371e24cfa489f11e8869cc3789f5cf/lib-jri/REngine.jar -------------------------------------------------------------------------------- /lib-jri/rtest2.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | 3 | import java.awt.*; 4 | import javax.swing.*; 5 | 6 | import org.rosuda.JRI.Rengine; 7 | import org.rosuda.JRI.REXP; 8 | import org.rosuda.JRI.RMainLoopCallbacks; 9 | import org.rosuda.JRI.RConsoleOutputStream; 10 | 11 | class TextConsole2 implements RMainLoopCallbacks 12 | { 13 | JFrame f; 14 | 15 | public JTextArea textarea = new JTextArea(); 16 | 17 | public TextConsole2() { 18 | f = new JFrame(); 19 | f.getContentPane().add(new JScrollPane(textarea)); 20 | f.setSize(new Dimension(800,600)); 21 | f.show(); 22 | } 23 | 24 | public void rWriteConsole(Rengine re, String text, int oType) { 25 | textarea.append(text); 26 | } 27 | 28 | public void rBusy(Rengine re, int which) { 29 | System.out.println("rBusy("+which+")"); 30 | } 31 | 32 | public String rReadConsole(Rengine re, String prompt, int addToHistory) { 33 | System.out.print(prompt); 34 | try { 35 | BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); 36 | String s=br.readLine(); 37 | return (s==null||s.length()==0)?s:s+"\n"; 38 | } catch (Exception e) { 39 | System.out.println("jriReadConsole exception: "+e.getMessage()); 40 | } 41 | return null; 42 | } 43 | 44 | public void rShowMessage(Rengine re, String message) { 45 | System.out.println("rShowMessage \""+message+"\""); 46 | } 47 | 48 | public String rChooseFile(Rengine re, int newFile) { 49 | FileDialog fd = new FileDialog(f, (newFile==0)?"Select a file":"Select a new file", (newFile==0)?FileDialog.LOAD:FileDialog.SAVE); 50 | fd.show(); 51 | String res=null; 52 | if (fd.getDirectory()!=null) res=fd.getDirectory(); 53 | if (fd.getFile()!=null) res=(res==null)?fd.getFile():(res+fd.getFile()); 54 | return res; 55 | } 56 | 57 | public void rFlushConsole (Rengine re) { 58 | } 59 | 60 | public void rLoadHistory (Rengine re, String filename) { 61 | } 62 | 63 | public void rSaveHistory (Rengine re, String filename) { 64 | } 65 | } 66 | 67 | public class rtest2 { 68 | public static void main(String[] args) { 69 | System.out.println("Press to continue (time to attach the debugger if necessary)"); 70 | try { System.in.read(); } catch(Exception e) {}; 71 | System.out.println("Creating Rengine (with arguments)"); 72 | Rengine re=new Rengine(args, true, new TextConsole2()); 73 | System.out.println("Rengine created, waiting for R"); 74 | if (!re.waitForR()) { 75 | System.out.println("Cannot load R"); 76 | return; 77 | } 78 | System.out.println("re-routing stdout/err into R console"); 79 | System.setOut(new PrintStream(new RConsoleOutputStream(re, 0))); 80 | System.setErr(new PrintStream(new RConsoleOutputStream(re, 1))); 81 | 82 | System.out.println("Letting go; use main loop from now on"); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib-rserve/REngine.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billberg/DiffWind/4f9afe56e7371e24cfa489f11e8869cc3789f5cf/lib-rserve/REngine.jar -------------------------------------------------------------------------------- /lib-rserve/RserveEngine.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billberg/DiffWind/4f9afe56e7371e24cfa489f11e8869cc3789f5cf/lib-rserve/RserveEngine.jar -------------------------------------------------------------------------------- /lib/cube-sdk-ext-1.0-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billberg/DiffWind/4f9afe56e7371e24cfa489f11e8869cc3789f5cf/lib/cube-sdk-ext-1.0-SNAPSHOT.jar -------------------------------------------------------------------------------- /lib/taobao-express-3.0.18.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billberg/DiffWind/4f9afe56e7371e24cfa489f11e8869cc3789f5cf/lib/taobao-express-3.0.18.jar -------------------------------------------------------------------------------- /mybatis-generator-core-1.3.2/generate.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billberg/DiffWind/4f9afe56e7371e24cfa489f11e8869cc3789f5cf/mybatis-generator-core-1.3.2/generate.bat -------------------------------------------------------------------------------- /mybatis-generator-core-1.3.2/generate.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | echo "generating..." 3 | java -jar ./mybatis-generator-core-1.3.2.jar -configfile ./generatorConfig-pg.xml -overwrite 4 | echo "finished" 5 | -------------------------------------------------------------------------------- /mybatis-generator-core-1.3.2/generatorConfig-MySQL.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
43 | 44 |
45 | 46 |
47 | -------------------------------------------------------------------------------- /mybatis-generator-core-1.3.2/generatorConfig-pg.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 95 | 96 |
97 |
98 | 99 |
-------------------------------------------------------------------------------- /mybatis-generator-core-1.3.2/mybatis-generator-core-1.3.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billberg/DiffWind/4f9afe56e7371e24cfa489f11e8869cc3789f5cf/mybatis-generator-core-1.3.2/mybatis-generator-core-1.3.2.jar -------------------------------------------------------------------------------- /mybatis-generator-core-1.3.2/mysql-connector-java-5.1.35.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billberg/DiffWind/4f9afe56e7371e24cfa489f11e8869cc3789f5cf/mybatis-generator-core-1.3.2/mysql-connector-java-5.1.35.jar -------------------------------------------------------------------------------- /mybatis-generator-core-1.3.2/postgresql-9.4.1208.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billberg/DiffWind/4f9afe56e7371e24cfa489f11e8869cc3789f5cf/mybatis-generator-core-1.3.2/postgresql-9.4.1208.jar -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.github.billberg 6 | DiffWind 7 | 1.0 8 | jar 9 | 10 | 11 | 3.2.2.RELEASE 12 | 1.9.10 13 | 1.8 14 | 15 | 16 | 17 | 18 | 19 | org.postgresql 20 | postgresql 21 | 9.4.1208 22 | 23 | 24 | 25 | org.mybatis 26 | mybatis 27 | 3.3.0 28 | 29 | 30 | 31 | net.sourceforge.htmlcleaner 32 | htmlcleaner 33 | 2.2 34 | 35 | 36 | 37 | com.google.code.gson 38 | gson 39 | 2.3.1 40 | 41 | 42 | 43 | 44 | com.alibaba 45 | fastjson 46 | 1.2.10 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | commons-lang 57 | commons-lang 58 | 2.6 59 | 60 | 61 | 62 | 63 | org.apache.commons 64 | commons-lang3 65 | 3.6 66 | 67 | 68 | 69 | org.apache.poi 70 | poi 71 | 3.17 72 | 73 | 74 | org.apache.poi 75 | poi-ooxml 76 | 3.17 77 | 78 | 79 | 80 | 81 | 82 | org.apache.logging.log4j 83 | log4j-api 84 | 2.11.0 85 | 86 | 87 | org.apache.logging.log4j 88 | log4j-core 89 | 2.11.0 90 | 91 | 92 | 93 | log4j 94 | log4j 95 | 1.2.15 96 | 97 | 98 | com.sun.jmx 99 | jmxri 100 | 101 | 102 | com.sun.jdmk 103 | jmxtools 104 | 105 | 106 | javax.jms 107 | jms 108 | 109 | 110 | 111 | 112 | 113 | org.apache.httpcomponents 114 | httpclient 115 | 4.5.1 116 | 117 | 118 | 119 | 120 | org.apache.commons 121 | commons-math3 122 | 3.5 123 | 124 | 125 | 126 | commons-beanutils 127 | commons-beanutils 128 | 1.9.3 129 | 130 | 131 | 132 | com.google.guava 133 | guava 134 | 23.6-jre 135 | 136 | 137 | 142 | 143 | 144 | junit 145 | junit 146 | 4.10 147 | test 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | org.apache.maven.plugins 156 | maven-eclipse-plugin 157 | 2.9 158 | 159 | true 160 | false 161 | 2.0 162 | 163 | 164 | 165 | org.apache.maven.plugins 166 | maven-compiler-plugin 167 | 3.1 168 | 169 | ${jdk.version} 170 | ${jdk.version} 171 | UTF-8 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | src/main/resources 180 | 181 | **/*.xml 182 | **/*.properties 183 | 184 | 185 | 186 | src/main/java 187 | 188 | **/*.xml 189 | 190 | 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/constants/DataSource.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.constants; 2 | 3 | public class DataSource { 4 | 5 | //页面:String eastmoney_rzrq = "http://data.eastmoney.com/rzrq/detail/000625.html"; 6 | //json数据:String eastmoney_rzrq = "http://dcfm.eastmoney.com/em_mutisvcexpandinterface/api/js/get?type=RZRQ_DETAIL_NJ&token=70f12f2f4f091e459a279469fe49eca5&filter=(scode=%27000625%27)&st=tdate&sr=-1&p=1&ps=50&js=var%20yKxpOsnj={pages:(tp),data:(x)}&time=1&rt=50294875"; 7 | //token为必输项 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/constants/Index.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.constants; 2 | 3 | import java.util.HashMap; 4 | 5 | public class Index { 6 | // 通达信指数代码 7 | public static final String[] indexSymbols = {"sh000300","sh999999","sz399001","sz399005","sz399006"}; 8 | public static final HashMap tdxIndex = new HashMap() { 9 | { 10 | put("sh999999", "上证指数"); 11 | put("sz399001", "深证成指"); 12 | put("sz399005", "中小板指"); 13 | put("sz399006", "创业板指"); 14 | put("sh000300", "沪深300"); 15 | } 16 | }; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapper/CreateIndexMapper.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao.mapper; 2 | 3 | import org.apache.ibatis.annotations.Param; 4 | 5 | public interface CreateIndexMapper { 6 | 7 | 8 | void createIndex(@Param("sql") String sql); 9 | 10 | void dropIndex(@Param("idx") String idx); 11 | 12 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapper/EastmoneyStockBbsjMapper.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao.mapper; 2 | 3 | import java.util.List; 4 | 5 | import com.diffwind.dao.model.EastmoneyStockBbsj; 6 | 7 | public interface EastmoneyStockBbsjMapper { 8 | /** 9 | * This method was generated by MyBatis Generator. 10 | * This method corresponds to the database table eastmoney_stock_bbsj 11 | * 12 | * @mbggenerated 13 | */ 14 | int insert(EastmoneyStockBbsj record); 15 | 16 | /** 17 | * This method was generated by MyBatis Generator. 18 | * This method corresponds to the database table eastmoney_stock_bbsj 19 | * 20 | * @mbggenerated 21 | */ 22 | List selectAll(); 23 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapper/EastmoneyStockRzrqJsonMapper.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao.mapper; 2 | 3 | import java.util.List; 4 | 5 | import com.diffwind.dao.model.EastmoneyStockRzrqJson; 6 | 7 | public interface EastmoneyStockRzrqJsonMapper { 8 | /** 9 | * This method was generated by MyBatis Generator. 10 | * This method corresponds to the database table eastmoney_stock_rzrq_json 11 | * 12 | * @mbggenerated 13 | */ 14 | int insert(EastmoneyStockRzrqJson record); 15 | 16 | /** 17 | * This method was generated by MyBatis Generator. 18 | * This method corresponds to the database table eastmoney_stock_rzrq_json 19 | * 20 | * @mbggenerated 21 | */ 22 | List selectAll(); 23 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapper/QueryMapper.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao.mapper; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | public interface QueryMapper { 7 | 8 | List selectBySuodeshui(List symbols); 9 | 10 | //金融行业 11 | List selectBySuodeshui_JinRong(List symbols); 12 | 13 | //单个查询性能太低 14 | @Deprecated 15 | List selectByShui(String symbol); 16 | @Deprecated 17 | List selectByShui_JinRong(String symbol); 18 | 19 | List selectIncomeStatementBySymbol(String symbol); 20 | //金融行业 21 | List selectIncomeStatementBySymbol_JinRong(String symbol); 22 | 23 | // 24 | List selectRzrqSymbols(); 25 | //融资融券数据 26 | List selectRzrqBySymbol(String symbol); 27 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapper/SinaStockMapper.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao.mapper; 2 | 3 | import java.util.List; 4 | 5 | import com.diffwind.dao.model.SinaStock; 6 | 7 | public interface SinaStockMapper { 8 | /** 9 | * This method was generated by MyBatis Generator. 10 | * This method corresponds to the database table sina_stock 11 | * 12 | * @mbggenerated 13 | */ 14 | int deleteByPrimaryKey(String symbol); 15 | 16 | /** 17 | * This method was generated by MyBatis Generator. 18 | * This method corresponds to the database table sina_stock 19 | * 20 | * @mbggenerated 21 | */ 22 | int insert(SinaStock record); 23 | 24 | /** 25 | * This method was generated by MyBatis Generator. 26 | * This method corresponds to the database table sina_stock 27 | * 28 | * @mbggenerated 29 | */ 30 | SinaStock selectByPrimaryKey(String symbol); 31 | 32 | /** 33 | * This method was generated by MyBatis Generator. 34 | * This method corresponds to the database table sina_stock 35 | * 36 | * @mbggenerated 37 | */ 38 | List selectAll(); 39 | 40 | /** 41 | * This method was generated by MyBatis Generator. 42 | * This method corresponds to the database table sina_stock 43 | * 44 | * @mbggenerated 45 | */ 46 | int updateByPrimaryKey(SinaStock record); 47 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapper/SinaZjhhangyeMapper.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao.mapper; 2 | 3 | import java.util.List; 4 | 5 | import com.diffwind.dao.model.SinaZjhhangye; 6 | 7 | public interface SinaZjhhangyeMapper { 8 | /** 9 | * This method was generated by MyBatis Generator. 10 | * This method corresponds to the database table sina_zjhhangye 11 | * 12 | * @mbggenerated 13 | */ 14 | int insert(SinaZjhhangye record); 15 | 16 | /** 17 | * This method was generated by MyBatis Generator. 18 | * This method corresponds to the database table sina_zjhhangye 19 | * 20 | * @mbggenerated 21 | */ 22 | List selectAll(); 23 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapper/SinaZjhhangyeStockMapper.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao.mapper; 2 | 3 | import java.util.List; 4 | 5 | import org.apache.ibatis.annotations.Param; 6 | 7 | import com.diffwind.dao.model.SinaZjhhangyeStock; 8 | 9 | public interface SinaZjhhangyeStockMapper { 10 | /** 11 | * This method was generated by MyBatis Generator. 12 | * This method corresponds to the database table sina_zjhhangye_stock 13 | * 14 | * @mbggenerated 15 | */ 16 | int insert(SinaZjhhangyeStock record); 17 | 18 | /** 19 | * This method was generated by MyBatis Generator. 20 | * This method corresponds to the database table sina_zjhhangye_stock 21 | * 22 | * @mbggenerated 23 | */ 24 | List selectAll(); 25 | 26 | 27 | List selectBySymbol(@Param("symbol") String symbol); 28 | 29 | List selectHyBySymbol(@Param("symbol") String symbol); 30 | 31 | List selectAllStockHangye(); 32 | 33 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapper/TdxStockDayMapper.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao.mapper; 2 | 3 | import java.util.List; 4 | 5 | import org.apache.ibatis.annotations.Param; 6 | 7 | import com.diffwind.dao.model.TdxStockDay; 8 | 9 | public interface TdxStockDayMapper { 10 | /** 11 | * This method was generated by MyBatis Generator. 12 | * This method corresponds to the database table tdx_stock_day 13 | * 14 | * @mbggenerated 15 | */ 16 | int insert(TdxStockDay record); 17 | 18 | /** 19 | * This method was generated by MyBatis Generator. 20 | * This method corresponds to the database table tdx_stock_day 21 | * 22 | * @mbggenerated 23 | */ 24 | List selectAll(); 25 | 26 | 27 | void batchInsert(@Param("records") List records); 28 | 29 | List selectBySymbol(@Param("symbol") String symbol, @Param("isDesc") boolean isDesc); 30 | 31 | void batchInsertPartition(@Param("partition") String partition, @Param("records") List records); 32 | 33 | void truncatePartition(@Param("partition") String partition); 34 | 35 | 36 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapper/TruncateTableMapper.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao.mapper; 2 | 3 | import org.apache.ibatis.annotations.Param; 4 | 5 | public interface TruncateTableMapper { 6 | 7 | //void createIndex(); 8 | 9 | // void dropIndex(); 10 | 11 | void truncateTable(@Param("tableName") String tableName); 12 | 13 | void swapTable(@Param("tableName") String tableName); 14 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapper/XueqiuStockFinanceMapper.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao.mapper; 2 | 3 | import java.util.List; 4 | 5 | import org.apache.ibatis.annotations.Param; 6 | 7 | import com.diffwind.dao.model.XueqiuStockFinance; 8 | 9 | public interface XueqiuStockFinanceMapper { 10 | /** 11 | * This method was generated by MyBatis Generator. 12 | * This method corresponds to the database table xueqiu_stock_finance 13 | * 14 | * @mbggenerated 15 | */ 16 | int insert(XueqiuStockFinance record); 17 | 18 | /** 19 | * This method was generated by MyBatis Generator. 20 | * This method corresponds to the database table xueqiu_stock_finance 21 | * 22 | * @mbggenerated 23 | */ 24 | List selectAll(); 25 | 26 | 27 | List selectBySymbol(@Param("symbol") String symbol); 28 | 29 | List selectAllStkLastReportdate(); 30 | 31 | List selectByYingli5Y(); 32 | 33 | List selectForClusterAnalysis(); 34 | 35 | List selectBySymbol5Y(@Param("symbol") String symbol); 36 | 37 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapper/XueqiuStockMapper.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao.mapper; 2 | 3 | import java.util.List; 4 | 5 | import com.diffwind.dao.model.XueqiuStock; 6 | 7 | public interface XueqiuStockMapper { 8 | /** 9 | * This method was generated by MyBatis Generator. 10 | * This method corresponds to the database table xueqiu_stock 11 | * 12 | * @mbggenerated 13 | */ 14 | int deleteByPrimaryKey(String symbol); 15 | 16 | /** 17 | * This method was generated by MyBatis Generator. 18 | * This method corresponds to the database table xueqiu_stock 19 | * 20 | * @mbggenerated 21 | */ 22 | int insert(XueqiuStock record); 23 | 24 | /** 25 | * This method was generated by MyBatis Generator. 26 | * This method corresponds to the database table xueqiu_stock 27 | * 28 | * @mbggenerated 29 | */ 30 | XueqiuStock selectByPrimaryKey(String symbol); 31 | 32 | /** 33 | * This method was generated by MyBatis Generator. 34 | * This method corresponds to the database table xueqiu_stock 35 | * 36 | * @mbggenerated 37 | */ 38 | List selectAll(); 39 | 40 | /** 41 | * This method was generated by MyBatis Generator. 42 | * This method corresponds to the database table xueqiu_stock 43 | * 44 | * @mbggenerated 45 | */ 46 | int updateByPrimaryKey(XueqiuStock record); 47 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapper/XueqiuStockShareschgMapper.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao.mapper; 2 | 3 | import java.util.List; 4 | 5 | import org.apache.ibatis.annotations.Param; 6 | 7 | import com.diffwind.dao.model.XueqiuStockShareschg; 8 | 9 | public interface XueqiuStockShareschgMapper { 10 | /** 11 | * This method was generated by MyBatis Generator. 12 | * This method corresponds to the database table xueqiu_stock_shareschg 13 | * 14 | * @mbggenerated 15 | */ 16 | int insert(XueqiuStockShareschg record); 17 | 18 | /** 19 | * This method was generated by MyBatis Generator. 20 | * This method corresponds to the database table xueqiu_stock_shareschg 21 | * 22 | * @mbggenerated 23 | */ 24 | List selectAll(); 25 | 26 | 27 | List selectBySymbol(@Param("symbol") String symbol); 28 | 29 | List selectAllStkLastShareschg(); 30 | 31 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapping/CreateIndexMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | create index ${sql} 7 | 8 | 9 | 10 | drop index if exists ${idx} 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapping/EastmoneyStockBbsjMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | insert into eastmoney_stock_bbsj (symbol, code, yuyue_date, 21 | pilu_date, finance_date) 22 | values (#{symbol,jdbcType=CHAR}, #{code,jdbcType=CHAR}, #{yuyueDate,jdbcType=DATE}, 23 | #{piluDate,jdbcType=DATE}, #{financeDate,jdbcType=DATE}) 24 | 25 | 33 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapping/EastmoneyStockRzrqJsonMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 16 | insert into eastmoney_stock_rzrq_json (rzrq_data) 17 | values (#{rzrqData,jdbcType=OTHER}) 18 | 19 | 27 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapping/SinaStockMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 18 | delete from sina_stock 19 | where symbol = #{symbol,jdbcType=CHAR} 20 | 21 | 22 | 26 | insert into sina_stock (symbol, code, name) 27 | values (#{symbol,jdbcType=CHAR}, #{code,jdbcType=CHAR}, #{name,jdbcType=VARCHAR}) 28 | 29 | 30 | 34 | update sina_stock 35 | set code = #{code,jdbcType=CHAR}, 36 | name = #{name,jdbcType=VARCHAR} 37 | where symbol = #{symbol,jdbcType=CHAR} 38 | 39 | 48 | 49 | 54 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapping/SinaZjhhangyeMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 17 | insert into sina_zjhhangye (code, name) 18 | values (#{code,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}) 19 | 20 | 28 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapping/SinaZjhhangyeStockMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | insert into sina_zjhhangye_stock (hycode, hyname, symbol, 20 | name) 21 | values (#{hycode,jdbcType=VARCHAR}, #{hyname,jdbcType=VARCHAR}, #{symbol,jdbcType=CHAR}, 22 | #{name,jdbcType=VARCHAR}) 23 | 24 | 32 | 33 | 34 | 40 | 41 | 47 | 48 | 49 | 54 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapping/TdxStockDayMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 23 | insert into tdx_stock_day (symbol, date, open, 24 | high, low, close, amt, 25 | vol) 26 | values (#{symbol,jdbcType=CHAR}, #{date,jdbcType=DATE}, #{open,jdbcType=DOUBLE}, 27 | #{high,jdbcType=DOUBLE}, #{low,jdbcType=DOUBLE}, #{close,jdbcType=DOUBLE}, #{amt,jdbcType=DOUBLE}, 28 | #{vol,jdbcType=DOUBLE}) 29 | 30 | 38 | 39 | 40 | 41 | insert into tdx_stock_day (symbol, date, open, 42 | high, low, close, amt, 43 | vol) 44 | values 45 | 46 | (#{item.symbol,jdbcType=CHAR}, #{item.date,jdbcType=DATE}, #{item.open,jdbcType=DOUBLE}, 47 | #{item.high,jdbcType=DOUBLE}, #{item.low,jdbcType=DOUBLE}, #{item.close,jdbcType=DOUBLE}, #{item.amt,jdbcType=DOUBLE}, 48 | #{item.vol,jdbcType=DOUBLE}) 49 | 50 | 51 | 52 | 53 | 54 | 66 | 67 | 68 | 69 | 70 | insert into "tdx_stock_day_${partition}" (symbol, date, open, 71 | high, low, close, amt, 72 | vol) 73 | values 74 | 75 | (#{item.symbol,jdbcType=CHAR}, #{item.date,jdbcType=DATE}, #{item.open,jdbcType=DOUBLE}, 76 | #{item.high,jdbcType=DOUBLE}, #{item.low,jdbcType=DOUBLE}, #{item.close,jdbcType=DOUBLE}, #{item.amt,jdbcType=DOUBLE}, 77 | #{item.vol,jdbcType=DOUBLE}) 78 | 79 | 80 | 81 | 82 | truncate table "tdx_stock_day_${partition}" 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapping/TruncateTableMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | truncate table "${tableName}" 7 | 8 | 9 | 10 | do $$declare 11 | begin 12 | ALTER table ${tableName} rename to ${tableName}_tmp; 13 | ALTER table ${tableName}_swap rename to ${tableName}; 14 | ALTER table ${tableName}_tmp rename to ${tableName}_swap; 15 | end$$ 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapping/XueqiuStockMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 18 | delete from xueqiu_stock 19 | where symbol = #{symbol,jdbcType=CHAR} 20 | 21 | 22 | 26 | insert into xueqiu_stock (symbol, code, name) 27 | values (#{symbol,jdbcType=CHAR}, #{code,jdbcType=CHAR}, #{name,jdbcType=VARCHAR}) 28 | 29 | 30 | 34 | update xueqiu_stock 35 | set code = #{code,jdbcType=CHAR}, 36 | name = #{name,jdbcType=VARCHAR} 37 | where symbol = #{symbol,jdbcType=CHAR} 38 | 39 | 48 | 56 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/mapping/XueqiuStockShareschgMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 24 | insert into xueqiu_stock_shareschg (symbol, publishdate, begindate, 25 | totalshare, totalsharechg, skchgexp, 26 | fcircskamt, circskamt, ncircamt 27 | ) 28 | values (#{symbol,jdbcType=CHAR}, #{publishdate,jdbcType=DATE}, #{begindate,jdbcType=DATE}, 29 | #{totalshare,jdbcType=DOUBLE}, #{totalsharechg,jdbcType=DOUBLE}, #{skchgexp,jdbcType=VARCHAR}, 30 | #{fcircskamt,jdbcType=DOUBLE}, #{circskamt,jdbcType=DOUBLE}, #{ncircamt,jdbcType=DOUBLE} 31 | ) 32 | 33 | 42 | 43 | 44 | 45 | 52 | 53 | 55 | 61 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/model/EastmoneyStockBbsj.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao.model; 2 | 3 | import java.util.Date; 4 | 5 | public class EastmoneyStockBbsj { 6 | /** 7 | * This field was generated by MyBatis Generator. 8 | * This field corresponds to the database column eastmoney_stock_bbsj.symbol 9 | * 10 | * @mbggenerated 11 | */ 12 | private String symbol; 13 | 14 | /** 15 | * This field was generated by MyBatis Generator. 16 | * This field corresponds to the database column eastmoney_stock_bbsj.code 17 | * 18 | * @mbggenerated 19 | */ 20 | private String code; 21 | 22 | /** 23 | * This field was generated by MyBatis Generator. 24 | * This field corresponds to the database column eastmoney_stock_bbsj.yuyue_date 25 | * 26 | * @mbggenerated 27 | */ 28 | private Date yuyueDate; 29 | 30 | /** 31 | * This field was generated by MyBatis Generator. 32 | * This field corresponds to the database column eastmoney_stock_bbsj.pilu_date 33 | * 34 | * @mbggenerated 35 | */ 36 | private Date piluDate; 37 | 38 | /** 39 | * This field was generated by MyBatis Generator. 40 | * This field corresponds to the database column eastmoney_stock_bbsj.finance_date 41 | * 42 | * @mbggenerated 43 | */ 44 | private Date financeDate; 45 | 46 | /** 47 | * This method was generated by MyBatis Generator. 48 | * This method returns the value of the database column eastmoney_stock_bbsj.symbol 49 | * 50 | * @return the value of eastmoney_stock_bbsj.symbol 51 | * 52 | * @mbggenerated 53 | */ 54 | public String getSymbol() { 55 | return symbol; 56 | } 57 | 58 | /** 59 | * This method was generated by MyBatis Generator. 60 | * This method sets the value of the database column eastmoney_stock_bbsj.symbol 61 | * 62 | * @param symbol the value for eastmoney_stock_bbsj.symbol 63 | * 64 | * @mbggenerated 65 | */ 66 | public void setSymbol(String symbol) { 67 | this.symbol = symbol == null ? null : symbol.trim(); 68 | } 69 | 70 | /** 71 | * This method was generated by MyBatis Generator. 72 | * This method returns the value of the database column eastmoney_stock_bbsj.code 73 | * 74 | * @return the value of eastmoney_stock_bbsj.code 75 | * 76 | * @mbggenerated 77 | */ 78 | public String getCode() { 79 | return code; 80 | } 81 | 82 | /** 83 | * This method was generated by MyBatis Generator. 84 | * This method sets the value of the database column eastmoney_stock_bbsj.code 85 | * 86 | * @param code the value for eastmoney_stock_bbsj.code 87 | * 88 | * @mbggenerated 89 | */ 90 | public void setCode(String code) { 91 | this.code = code == null ? null : code.trim(); 92 | } 93 | 94 | /** 95 | * This method was generated by MyBatis Generator. 96 | * This method returns the value of the database column eastmoney_stock_bbsj.yuyue_date 97 | * 98 | * @return the value of eastmoney_stock_bbsj.yuyue_date 99 | * 100 | * @mbggenerated 101 | */ 102 | public Date getYuyueDate() { 103 | return yuyueDate; 104 | } 105 | 106 | /** 107 | * This method was generated by MyBatis Generator. 108 | * This method sets the value of the database column eastmoney_stock_bbsj.yuyue_date 109 | * 110 | * @param yuyueDate the value for eastmoney_stock_bbsj.yuyue_date 111 | * 112 | * @mbggenerated 113 | */ 114 | public void setYuyueDate(Date yuyueDate) { 115 | this.yuyueDate = yuyueDate; 116 | } 117 | 118 | /** 119 | * This method was generated by MyBatis Generator. 120 | * This method returns the value of the database column eastmoney_stock_bbsj.pilu_date 121 | * 122 | * @return the value of eastmoney_stock_bbsj.pilu_date 123 | * 124 | * @mbggenerated 125 | */ 126 | public Date getPiluDate() { 127 | return piluDate; 128 | } 129 | 130 | /** 131 | * This method was generated by MyBatis Generator. 132 | * This method sets the value of the database column eastmoney_stock_bbsj.pilu_date 133 | * 134 | * @param piluDate the value for eastmoney_stock_bbsj.pilu_date 135 | * 136 | * @mbggenerated 137 | */ 138 | public void setPiluDate(Date piluDate) { 139 | this.piluDate = piluDate; 140 | } 141 | 142 | /** 143 | * This method was generated by MyBatis Generator. 144 | * This method returns the value of the database column eastmoney_stock_bbsj.finance_date 145 | * 146 | * @return the value of eastmoney_stock_bbsj.finance_date 147 | * 148 | * @mbggenerated 149 | */ 150 | public Date getFinanceDate() { 151 | return financeDate; 152 | } 153 | 154 | /** 155 | * This method was generated by MyBatis Generator. 156 | * This method sets the value of the database column eastmoney_stock_bbsj.finance_date 157 | * 158 | * @param financeDate the value for eastmoney_stock_bbsj.finance_date 159 | * 160 | * @mbggenerated 161 | */ 162 | public void setFinanceDate(Date financeDate) { 163 | this.financeDate = financeDate; 164 | } 165 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/model/EastmoneyStockRzrqJson.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao.model; 2 | 3 | public class EastmoneyStockRzrqJson { 4 | /** 5 | * This field was generated by MyBatis Generator. 6 | * This field corresponds to the database column eastmoney_stock_rzrq_json.rzrq_data 7 | * 8 | * @mbggenerated 9 | */ 10 | private Object rzrqData; 11 | 12 | /** 13 | * This method was generated by MyBatis Generator. 14 | * This method returns the value of the database column eastmoney_stock_rzrq_json.rzrq_data 15 | * 16 | * @return the value of eastmoney_stock_rzrq_json.rzrq_data 17 | * 18 | * @mbggenerated 19 | */ 20 | public Object getRzrqData() { 21 | return rzrqData; 22 | } 23 | 24 | /** 25 | * This method was generated by MyBatis Generator. 26 | * This method sets the value of the database column eastmoney_stock_rzrq_json.rzrq_data 27 | * 28 | * @param rzrqData the value for eastmoney_stock_rzrq_json.rzrq_data 29 | * 30 | * @mbggenerated 31 | */ 32 | public void setRzrqData(Object rzrqData) { 33 | this.rzrqData = rzrqData; 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/model/SinaStock.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao.model; 2 | 3 | public class SinaStock { 4 | /** 5 | * This field was generated by MyBatis Generator. 6 | * This field corresponds to the database column sina_stock.symbol 7 | * 8 | * @mbggenerated 9 | */ 10 | private String symbol; 11 | 12 | /** 13 | * This field was generated by MyBatis Generator. 14 | * This field corresponds to the database column sina_stock.code 15 | * 16 | * @mbggenerated 17 | */ 18 | private String code; 19 | 20 | /** 21 | * This field was generated by MyBatis Generator. 22 | * This field corresponds to the database column sina_stock.name 23 | * 24 | * @mbggenerated 25 | */ 26 | private String name; 27 | 28 | /** 29 | * This method was generated by MyBatis Generator. 30 | * This method returns the value of the database column sina_stock.symbol 31 | * 32 | * @return the value of sina_stock.symbol 33 | * 34 | * @mbggenerated 35 | */ 36 | public String getSymbol() { 37 | return symbol; 38 | } 39 | 40 | /** 41 | * This method was generated by MyBatis Generator. 42 | * This method sets the value of the database column sina_stock.symbol 43 | * 44 | * @param symbol the value for sina_stock.symbol 45 | * 46 | * @mbggenerated 47 | */ 48 | public void setSymbol(String symbol) { 49 | this.symbol = symbol == null ? null : symbol.trim(); 50 | } 51 | 52 | /** 53 | * This method was generated by MyBatis Generator. 54 | * This method returns the value of the database column sina_stock.code 55 | * 56 | * @return the value of sina_stock.code 57 | * 58 | * @mbggenerated 59 | */ 60 | public String getCode() { 61 | return code; 62 | } 63 | 64 | /** 65 | * This method was generated by MyBatis Generator. 66 | * This method sets the value of the database column sina_stock.code 67 | * 68 | * @param code the value for sina_stock.code 69 | * 70 | * @mbggenerated 71 | */ 72 | public void setCode(String code) { 73 | this.code = code == null ? null : code.trim(); 74 | } 75 | 76 | /** 77 | * This method was generated by MyBatis Generator. 78 | * This method returns the value of the database column sina_stock.name 79 | * 80 | * @return the value of sina_stock.name 81 | * 82 | * @mbggenerated 83 | */ 84 | public String getName() { 85 | return name; 86 | } 87 | 88 | /** 89 | * This method was generated by MyBatis Generator. 90 | * This method sets the value of the database column sina_stock.name 91 | * 92 | * @param name the value for sina_stock.name 93 | * 94 | * @mbggenerated 95 | */ 96 | public void setName(String name) { 97 | this.name = name == null ? null : name.trim(); 98 | } 99 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/model/SinaZjhhangye.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao.model; 2 | 3 | public class SinaZjhhangye { 4 | /** 5 | * This field was generated by MyBatis Generator. 6 | * This field corresponds to the database column sina_zjhhangye.code 7 | * 8 | * @mbggenerated 9 | */ 10 | private String code; 11 | 12 | /** 13 | * This field was generated by MyBatis Generator. 14 | * This field corresponds to the database column sina_zjhhangye.name 15 | * 16 | * @mbggenerated 17 | */ 18 | private String name; 19 | 20 | /** 21 | * This method was generated by MyBatis Generator. 22 | * This method returns the value of the database column sina_zjhhangye.code 23 | * 24 | * @return the value of sina_zjhhangye.code 25 | * 26 | * @mbggenerated 27 | */ 28 | public String getCode() { 29 | return code; 30 | } 31 | 32 | /** 33 | * This method was generated by MyBatis Generator. 34 | * This method sets the value of the database column sina_zjhhangye.code 35 | * 36 | * @param code the value for sina_zjhhangye.code 37 | * 38 | * @mbggenerated 39 | */ 40 | public void setCode(String code) { 41 | this.code = code == null ? null : code.trim(); 42 | } 43 | 44 | /** 45 | * This method was generated by MyBatis Generator. 46 | * This method returns the value of the database column sina_zjhhangye.name 47 | * 48 | * @return the value of sina_zjhhangye.name 49 | * 50 | * @mbggenerated 51 | */ 52 | public String getName() { 53 | return name; 54 | } 55 | 56 | /** 57 | * This method was generated by MyBatis Generator. 58 | * This method sets the value of the database column sina_zjhhangye.name 59 | * 60 | * @param name the value for sina_zjhhangye.name 61 | * 62 | * @mbggenerated 63 | */ 64 | public void setName(String name) { 65 | this.name = name == null ? null : name.trim(); 66 | } 67 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/model/SinaZjhhangyeStock.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao.model; 2 | 3 | public class SinaZjhhangyeStock { 4 | /** 5 | * This field was generated by MyBatis Generator. 6 | * This field corresponds to the database column sina_zjhhangye_stock.hycode 7 | * 8 | * @mbggenerated 9 | */ 10 | private String hycode; 11 | 12 | /** 13 | * This field was generated by MyBatis Generator. 14 | * This field corresponds to the database column sina_zjhhangye_stock.hyname 15 | * 16 | * @mbggenerated 17 | */ 18 | private String hyname; 19 | 20 | /** 21 | * This field was generated by MyBatis Generator. 22 | * This field corresponds to the database column sina_zjhhangye_stock.symbol 23 | * 24 | * @mbggenerated 25 | */ 26 | private String symbol; 27 | 28 | /** 29 | * This field was generated by MyBatis Generator. 30 | * This field corresponds to the database column sina_zjhhangye_stock.name 31 | * 32 | * @mbggenerated 33 | */ 34 | private String name; 35 | 36 | /** 37 | * This method was generated by MyBatis Generator. 38 | * This method returns the value of the database column sina_zjhhangye_stock.hycode 39 | * 40 | * @return the value of sina_zjhhangye_stock.hycode 41 | * 42 | * @mbggenerated 43 | */ 44 | public String getHycode() { 45 | return hycode; 46 | } 47 | 48 | /** 49 | * This method was generated by MyBatis Generator. 50 | * This method sets the value of the database column sina_zjhhangye_stock.hycode 51 | * 52 | * @param hycode the value for sina_zjhhangye_stock.hycode 53 | * 54 | * @mbggenerated 55 | */ 56 | public void setHycode(String hycode) { 57 | this.hycode = hycode == null ? null : hycode.trim(); 58 | } 59 | 60 | /** 61 | * This method was generated by MyBatis Generator. 62 | * This method returns the value of the database column sina_zjhhangye_stock.hyname 63 | * 64 | * @return the value of sina_zjhhangye_stock.hyname 65 | * 66 | * @mbggenerated 67 | */ 68 | public String getHyname() { 69 | return hyname; 70 | } 71 | 72 | /** 73 | * This method was generated by MyBatis Generator. 74 | * This method sets the value of the database column sina_zjhhangye_stock.hyname 75 | * 76 | * @param hyname the value for sina_zjhhangye_stock.hyname 77 | * 78 | * @mbggenerated 79 | */ 80 | public void setHyname(String hyname) { 81 | this.hyname = hyname == null ? null : hyname.trim(); 82 | } 83 | 84 | /** 85 | * This method was generated by MyBatis Generator. 86 | * This method returns the value of the database column sina_zjhhangye_stock.symbol 87 | * 88 | * @return the value of sina_zjhhangye_stock.symbol 89 | * 90 | * @mbggenerated 91 | */ 92 | public String getSymbol() { 93 | return symbol; 94 | } 95 | 96 | /** 97 | * This method was generated by MyBatis Generator. 98 | * This method sets the value of the database column sina_zjhhangye_stock.symbol 99 | * 100 | * @param symbol the value for sina_zjhhangye_stock.symbol 101 | * 102 | * @mbggenerated 103 | */ 104 | public void setSymbol(String symbol) { 105 | this.symbol = symbol == null ? null : symbol.trim(); 106 | } 107 | 108 | /** 109 | * This method was generated by MyBatis Generator. 110 | * This method returns the value of the database column sina_zjhhangye_stock.name 111 | * 112 | * @return the value of sina_zjhhangye_stock.name 113 | * 114 | * @mbggenerated 115 | */ 116 | public String getName() { 117 | return name; 118 | } 119 | 120 | /** 121 | * This method was generated by MyBatis Generator. 122 | * This method sets the value of the database column sina_zjhhangye_stock.name 123 | * 124 | * @param name the value for sina_zjhhangye_stock.name 125 | * 126 | * @mbggenerated 127 | */ 128 | public void setName(String name) { 129 | this.name = name == null ? null : name.trim(); 130 | } 131 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/model/TdxStockDay.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao.model; 2 | 3 | import java.util.Date; 4 | 5 | public class TdxStockDay { 6 | /** 7 | * This field was generated by MyBatis Generator. 8 | * This field corresponds to the database column tdx_stock_day.symbol 9 | * 10 | * @mbggenerated 11 | */ 12 | private String symbol; 13 | 14 | /** 15 | * This field was generated by MyBatis Generator. 16 | * This field corresponds to the database column tdx_stock_day.date 17 | * 18 | * @mbggenerated 19 | */ 20 | private Date date; 21 | 22 | /** 23 | * This field was generated by MyBatis Generator. 24 | * This field corresponds to the database column tdx_stock_day.open 25 | * 26 | * @mbggenerated 27 | */ 28 | private Double open; 29 | 30 | /** 31 | * This field was generated by MyBatis Generator. 32 | * This field corresponds to the database column tdx_stock_day.high 33 | * 34 | * @mbggenerated 35 | */ 36 | private Double high; 37 | 38 | /** 39 | * This field was generated by MyBatis Generator. 40 | * This field corresponds to the database column tdx_stock_day.low 41 | * 42 | * @mbggenerated 43 | */ 44 | private Double low; 45 | 46 | /** 47 | * This field was generated by MyBatis Generator. 48 | * This field corresponds to the database column tdx_stock_day.close 49 | * 50 | * @mbggenerated 51 | */ 52 | private Double close; 53 | 54 | /** 55 | * This field was generated by MyBatis Generator. 56 | * This field corresponds to the database column tdx_stock_day.amt 57 | * 58 | * @mbggenerated 59 | */ 60 | private Double amt; 61 | 62 | /** 63 | * This field was generated by MyBatis Generator. 64 | * This field corresponds to the database column tdx_stock_day.vol 65 | * 66 | * @mbggenerated 67 | */ 68 | private Double vol; 69 | 70 | /** 71 | * This method was generated by MyBatis Generator. 72 | * This method returns the value of the database column tdx_stock_day.symbol 73 | * 74 | * @return the value of tdx_stock_day.symbol 75 | * 76 | * @mbggenerated 77 | */ 78 | public String getSymbol() { 79 | return symbol; 80 | } 81 | 82 | /** 83 | * This method was generated by MyBatis Generator. 84 | * This method sets the value of the database column tdx_stock_day.symbol 85 | * 86 | * @param symbol the value for tdx_stock_day.symbol 87 | * 88 | * @mbggenerated 89 | */ 90 | public void setSymbol(String symbol) { 91 | this.symbol = symbol == null ? null : symbol.trim(); 92 | } 93 | 94 | /** 95 | * This method was generated by MyBatis Generator. 96 | * This method returns the value of the database column tdx_stock_day.date 97 | * 98 | * @return the value of tdx_stock_day.date 99 | * 100 | * @mbggenerated 101 | */ 102 | public Date getDate() { 103 | return date; 104 | } 105 | 106 | /** 107 | * This method was generated by MyBatis Generator. 108 | * This method sets the value of the database column tdx_stock_day.date 109 | * 110 | * @param date the value for tdx_stock_day.date 111 | * 112 | * @mbggenerated 113 | */ 114 | public void setDate(Date date) { 115 | this.date = date; 116 | } 117 | 118 | /** 119 | * This method was generated by MyBatis Generator. 120 | * This method returns the value of the database column tdx_stock_day.open 121 | * 122 | * @return the value of tdx_stock_day.open 123 | * 124 | * @mbggenerated 125 | */ 126 | public Double getOpen() { 127 | return open; 128 | } 129 | 130 | /** 131 | * This method was generated by MyBatis Generator. 132 | * This method sets the value of the database column tdx_stock_day.open 133 | * 134 | * @param open the value for tdx_stock_day.open 135 | * 136 | * @mbggenerated 137 | */ 138 | public void setOpen(Double open) { 139 | this.open = open; 140 | } 141 | 142 | /** 143 | * This method was generated by MyBatis Generator. 144 | * This method returns the value of the database column tdx_stock_day.high 145 | * 146 | * @return the value of tdx_stock_day.high 147 | * 148 | * @mbggenerated 149 | */ 150 | public Double getHigh() { 151 | return high; 152 | } 153 | 154 | /** 155 | * This method was generated by MyBatis Generator. 156 | * This method sets the value of the database column tdx_stock_day.high 157 | * 158 | * @param high the value for tdx_stock_day.high 159 | * 160 | * @mbggenerated 161 | */ 162 | public void setHigh(Double high) { 163 | this.high = high; 164 | } 165 | 166 | /** 167 | * This method was generated by MyBatis Generator. 168 | * This method returns the value of the database column tdx_stock_day.low 169 | * 170 | * @return the value of tdx_stock_day.low 171 | * 172 | * @mbggenerated 173 | */ 174 | public Double getLow() { 175 | return low; 176 | } 177 | 178 | /** 179 | * This method was generated by MyBatis Generator. 180 | * This method sets the value of the database column tdx_stock_day.low 181 | * 182 | * @param low the value for tdx_stock_day.low 183 | * 184 | * @mbggenerated 185 | */ 186 | public void setLow(Double low) { 187 | this.low = low; 188 | } 189 | 190 | /** 191 | * This method was generated by MyBatis Generator. 192 | * This method returns the value of the database column tdx_stock_day.close 193 | * 194 | * @return the value of tdx_stock_day.close 195 | * 196 | * @mbggenerated 197 | */ 198 | public Double getClose() { 199 | return close; 200 | } 201 | 202 | /** 203 | * This method was generated by MyBatis Generator. 204 | * This method sets the value of the database column tdx_stock_day.close 205 | * 206 | * @param close the value for tdx_stock_day.close 207 | * 208 | * @mbggenerated 209 | */ 210 | public void setClose(Double close) { 211 | this.close = close; 212 | } 213 | 214 | /** 215 | * This method was generated by MyBatis Generator. 216 | * This method returns the value of the database column tdx_stock_day.amt 217 | * 218 | * @return the value of tdx_stock_day.amt 219 | * 220 | * @mbggenerated 221 | */ 222 | public Double getAmt() { 223 | return amt; 224 | } 225 | 226 | /** 227 | * This method was generated by MyBatis Generator. 228 | * This method sets the value of the database column tdx_stock_day.amt 229 | * 230 | * @param amt the value for tdx_stock_day.amt 231 | * 232 | * @mbggenerated 233 | */ 234 | public void setAmt(Double amt) { 235 | this.amt = amt; 236 | } 237 | 238 | /** 239 | * This method was generated by MyBatis Generator. 240 | * This method returns the value of the database column tdx_stock_day.vol 241 | * 242 | * @return the value of tdx_stock_day.vol 243 | * 244 | * @mbggenerated 245 | */ 246 | public Double getVol() { 247 | return vol; 248 | } 249 | 250 | /** 251 | * This method was generated by MyBatis Generator. 252 | * This method sets the value of the database column tdx_stock_day.vol 253 | * 254 | * @param vol the value for tdx_stock_day.vol 255 | * 256 | * @mbggenerated 257 | */ 258 | public void setVol(Double vol) { 259 | this.vol = vol; 260 | } 261 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/model/XueqiuStock.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao.model; 2 | 3 | public class XueqiuStock { 4 | /** 5 | * This field was generated by MyBatis Generator. 6 | * This field corresponds to the database column xueqiu_stock.symbol 7 | * 8 | * @mbggenerated 9 | */ 10 | private String symbol; 11 | 12 | /** 13 | * This field was generated by MyBatis Generator. 14 | * This field corresponds to the database column xueqiu_stock.code 15 | * 16 | * @mbggenerated 17 | */ 18 | private String code; 19 | 20 | /** 21 | * This field was generated by MyBatis Generator. 22 | * This field corresponds to the database column xueqiu_stock.name 23 | * 24 | * @mbggenerated 25 | */ 26 | private String name; 27 | 28 | /** 29 | * This method was generated by MyBatis Generator. 30 | * This method returns the value of the database column xueqiu_stock.symbol 31 | * 32 | * @return the value of xueqiu_stock.symbol 33 | * 34 | * @mbggenerated 35 | */ 36 | public String getSymbol() { 37 | return symbol; 38 | } 39 | 40 | /** 41 | * This method was generated by MyBatis Generator. 42 | * This method sets the value of the database column xueqiu_stock.symbol 43 | * 44 | * @param symbol the value for xueqiu_stock.symbol 45 | * 46 | * @mbggenerated 47 | */ 48 | public void setSymbol(String symbol) { 49 | this.symbol = symbol == null ? null : symbol.trim(); 50 | } 51 | 52 | /** 53 | * This method was generated by MyBatis Generator. 54 | * This method returns the value of the database column xueqiu_stock.code 55 | * 56 | * @return the value of xueqiu_stock.code 57 | * 58 | * @mbggenerated 59 | */ 60 | public String getCode() { 61 | return code; 62 | } 63 | 64 | /** 65 | * This method was generated by MyBatis Generator. 66 | * This method sets the value of the database column xueqiu_stock.code 67 | * 68 | * @param code the value for xueqiu_stock.code 69 | * 70 | * @mbggenerated 71 | */ 72 | public void setCode(String code) { 73 | this.code = code == null ? null : code.trim(); 74 | } 75 | 76 | /** 77 | * This method was generated by MyBatis Generator. 78 | * This method returns the value of the database column xueqiu_stock.name 79 | * 80 | * @return the value of xueqiu_stock.name 81 | * 82 | * @mbggenerated 83 | */ 84 | public String getName() { 85 | return name; 86 | } 87 | 88 | /** 89 | * This method was generated by MyBatis Generator. 90 | * This method sets the value of the database column xueqiu_stock.name 91 | * 92 | * @param name the value for xueqiu_stock.name 93 | * 94 | * @mbggenerated 95 | */ 96 | public void setName(String name) { 97 | this.name = name == null ? null : name.trim(); 98 | } 99 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/dao/util/TableUtil.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao.util; 2 | 3 | import java.io.IOException; 4 | import java.util.List; 5 | import java.util.concurrent.BlockingQueue; 6 | import java.util.concurrent.LinkedBlockingQueue; 7 | import java.util.concurrent.Semaphore; 8 | import java.util.concurrent.ThreadPoolExecutor; 9 | import java.util.concurrent.TimeUnit; 10 | import java.util.concurrent.atomic.AtomicInteger; 11 | 12 | import org.apache.ibatis.io.Resources; 13 | import org.apache.ibatis.session.SqlSession; 14 | import org.apache.ibatis.session.SqlSessionFactory; 15 | import org.apache.ibatis.session.SqlSessionFactoryBuilder; 16 | import org.apache.log4j.Logger; 17 | 18 | import com.diffwind.dao.mapper.CreateIndexMapper; 19 | import com.diffwind.dao.mapper.SinaStockMapper; 20 | import com.diffwind.dao.mapper.TruncateTableMapper; 21 | import com.diffwind.dao.model.SinaStock; 22 | 23 | public class TableUtil { 24 | 25 | private static Logger logger = Logger.getLogger(TableUtil.class); 26 | 27 | private static BlockingQueue workQueue = new LinkedBlockingQueue(100); 28 | private static ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 2, 1, TimeUnit.MINUTES, workQueue); 29 | private static Semaphore semaFinishedCount = new Semaphore(0); 30 | private static AtomicInteger finishedCount = new AtomicInteger(); 31 | 32 | private static List allStocks = null; 33 | private static SqlSessionFactory sqlSessionFactory = null; 34 | static { 35 | executor.allowCoreThreadTimeOut(true); 36 | // SqlSessionFactory sessionFactory = null; 37 | String resource = "mybatis-config.xml"; 38 | try { 39 | sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources 40 | .getResourceAsReader(resource)); 41 | 42 | SqlSession sqlSession = sqlSessionFactory.openSession(true); 43 | SinaStockMapper sinaStockMapper = sqlSession.getMapper(SinaStockMapper.class); 44 | allStocks = sinaStockMapper.selectAll(); 45 | sqlSession.close(); 46 | 47 | } catch (IOException e) { 48 | logger.error("mybatis config error", e); 49 | throw new RuntimeException("mybatis config error",e); 50 | } 51 | } 52 | 53 | 54 | private static void truncateTable(String tableName) { 55 | SqlSession sqlSession = sqlSessionFactory.openSession(true); 56 | 57 | TruncateTableMapper truncateTableMapper = sqlSession.getMapper(TruncateTableMapper.class); 58 | 59 | truncateTableMapper.truncateTable(tableName); 60 | 61 | sqlSession.close(); 62 | 63 | } 64 | 65 | private static void createIndex(String sql) { 66 | SqlSession sqlSession = sqlSessionFactory.openSession(true); 67 | CreateIndexMapper createIndexMapper = sqlSession.getMapper(CreateIndexMapper.class); 68 | 69 | createIndexMapper.createIndex(sql); 70 | 71 | sqlSession.close(); 72 | 73 | } 74 | 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/data/SinaHqDataRobot.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.data; 2 | 3 | import java.io.IOException; 4 | import java.text.MessageFormat; 5 | 6 | import org.apache.ibatis.io.Resources; 7 | import org.apache.ibatis.session.SqlSession; 8 | import org.apache.ibatis.session.SqlSessionFactory; 9 | import org.apache.ibatis.session.SqlSessionFactoryBuilder; 10 | import org.apache.log4j.Logger; 11 | 12 | import com.alibaba.fastjson.JSON; 13 | import com.alibaba.fastjson.JSONArray; 14 | import com.alibaba.fastjson.JSONObject; 15 | import com.diffwind.dao.mapper.SinaStockMapper; 16 | import com.diffwind.dao.mapper.TruncateTableMapper; 17 | import com.diffwind.dao.model.SinaStock; 18 | import com.diffwind.util.HttpUtil; 19 | 20 | /** 21 | * 22 | * 23 | * @author Billberg 24 | * 25 | */ 26 | public class SinaHqDataRobot { 27 | 28 | private static String USER_AGENT = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"; 29 | // private static String COOKIE = 30 | // "U_TRS1=0000003c.f03c375f.529bf08e.308fd6b8; 31 | // U_TRS2=0000003c.f04b375f.529bf08e.a0acac2d; 32 | // UOR=,money.finance.sina.com.cn,; 33 | // ULV=1385951383960:2:2:2:124.205.103.60_1385951379.311157:1385951380642; 34 | // SINAGLOBAL=124.205.103.60_1385951379.311153; 35 | // Apache=124.205.103.60_1385951379.311157; 36 | // vjuids=-84458cc30.142b123c4eb.0.338a6f04bb15b8; 37 | // vjlast=1385951381.1385951381.10; _s_upa=1; 38 | // Suda_uid=124.205.103.60_1385951379.311159"; 39 | private static String REFERER = "http://vip.stock.finance.sina.com.cn/"; 40 | 41 | // type=11/12 个股/指数 42 | // private static String RZRQ_SOURCE = 43 | // "https://xueqiu.com/stock/cata/stocklist.json?page={0}&size=100&order=desc&orderby=percent&type=11%2C12"; 44 | // private static String RZRQ_SOURCE = 45 | // "https://xueqiu.com/stock/cata/stocklist.json?page={0}&size={1}&order=desc&orderby=percent&type=11"; 46 | 47 | //注:不包含停牌股 48 | private static String SINA_HQ = "http://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/Market_Center.getHQNodeData?page={0}&num={1}&sort=changepercent&asc=0&node=hs_a&symbol=&_s_r_a=page"; 49 | // private static String XUEQIU_SZA = 50 | // "https://xueqiu.com/stock/quote_order.json?page={0}&size={1}&order=desc&exchange=CN&stockType=sza&column=symbol%2Cname%2Ccurrent%2Cchg%2Cpercent%2Clast_close%2Copen%2Chigh%2Clow%2Cvolume%2Camount%2Cmarket_capital%2Cpe_ttm%2Chigh52w%2Clow52w%2Chasexist&orderBy=percent"; 51 | 52 | private static int PAGE_SIZE = 80; 53 | private static int PAGE_COUNT = 50; 54 | 55 | private static String SOURCE_ENCODE = "utf-8"; 56 | private static String OUTPUT_ENCODE = "utf-8"; 57 | 58 | private static Logger logger = Logger.getLogger(SinaHqDataRobot.class); 59 | 60 | private static SqlSessionFactory sqlSessionFactory = null; 61 | 62 | static { 63 | // SqlSessionFactory sessionFactory = null; 64 | String resource = "mybatis-config.xml"; 65 | try { 66 | sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource)); 67 | } catch (IOException e) { 68 | logger.error("mybatis config error", e); 69 | throw new RuntimeException("mybatis config error", e); 70 | } 71 | } 72 | 73 | private static void updateXueqiuStock() { 74 | 75 | SqlSession sqlSession = null; 76 | 77 | try { 78 | 79 | sqlSession = sqlSessionFactory.openSession(true); 80 | 81 | TruncateTableMapper truncateTableMapper = sqlSession.getMapper(TruncateTableMapper.class); 82 | 83 | truncateTableMapper.truncateTable("sina_stock"); 84 | 85 | SinaStockMapper xqStockMapper = sqlSession.getMapper(SinaStockMapper.class); 86 | 87 | for (int p = 1; p <= PAGE_COUNT; p++) { 88 | String requestUrl = MessageFormat.format(SINA_HQ, p, PAGE_SIZE); 89 | 90 | HttpUtil httpUtil = new HttpUtil(); 91 | httpUtil.setRequestUrl(requestUrl); 92 | String response = httpUtil.doGet(); 93 | 94 | if (response == null || response.trim().equals("null")) { 95 | logger.info("sina hq data download finished"); 96 | break; 97 | } 98 | 99 | JSONArray stocks = JSON.parseArray(response); 100 | 101 | if (stocks.size() == 0) { 102 | logger.info("sina hq data download finished"); 103 | break; 104 | } 105 | 106 | for (int i = 0; i < stocks.size(); i++) { 107 | SinaStock xqStock = stocks.getObject(i, 108 | SinaStock.class); 109 | 110 | xqStockMapper.insert(xqStock); 111 | 112 | } 113 | 114 | } 115 | 116 | 117 | } catch (Exception e) { 118 | logger.error("updateXueqiuStock出错", e); 119 | } finally { 120 | sqlSession.close(); 121 | } 122 | } 123 | 124 | public static void main(String[] args) { 125 | 126 | updateXueqiuStock(); 127 | } 128 | 129 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/data/XueqiuHqDataRobot.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.data; 2 | 3 | import java.io.IOException; 4 | import java.text.MessageFormat; 5 | 6 | import org.apache.ibatis.io.Resources; 7 | import org.apache.ibatis.session.SqlSession; 8 | import org.apache.ibatis.session.SqlSessionFactory; 9 | import org.apache.ibatis.session.SqlSessionFactoryBuilder; 10 | import org.apache.log4j.Logger; 11 | 12 | import com.alibaba.fastjson.JSON; 13 | import com.alibaba.fastjson.JSONArray; 14 | import com.alibaba.fastjson.JSONObject; 15 | import com.diffwind.dao.mapper.TruncateTableMapper; 16 | import com.diffwind.dao.mapper.XueqiuStockMapper; 17 | import com.diffwind.dao.model.XueqiuStock; 18 | import com.diffwind.util.HttpUtil; 19 | 20 | /** 21 | * 22 | * 23 | * @author Billberg 24 | * 25 | */ 26 | public class XueqiuHqDataRobot { 27 | 28 | private static String USER_AGENT = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"; 29 | // private static String COOKIE = 30 | // "U_TRS1=0000003c.f03c375f.529bf08e.308fd6b8; 31 | // U_TRS2=0000003c.f04b375f.529bf08e.a0acac2d; 32 | // UOR=,money.finance.sina.com.cn,; 33 | // ULV=1385951383960:2:2:2:124.205.103.60_1385951379.311157:1385951380642; 34 | // SINAGLOBAL=124.205.103.60_1385951379.311153; 35 | // Apache=124.205.103.60_1385951379.311157; 36 | // vjuids=-84458cc30.142b123c4eb.0.338a6f04bb15b8; 37 | // vjlast=1385951381.1385951381.10; _s_upa=1; 38 | // Suda_uid=124.205.103.60_1385951379.311159"; 39 | private static String REFERER = "https://xueqiu.com"; 40 | 41 | // type=11/12 个股/指数 42 | // private static String RZRQ_SOURCE = 43 | // "https://xueqiu.com/stock/cata/stocklist.json?page={0}&size=100&order=desc&orderby=percent&type=11%2C12"; 44 | // private static String RZRQ_SOURCE = 45 | // "https://xueqiu.com/stock/cata/stocklist.json?page={0}&size={1}&order=desc&orderby=percent&type=11"; 46 | 47 | //注:不包含停牌股 48 | private static String XUEQIU_HQ = "https://xueqiu.com/stock/quote_order.json?page={0}&size={1}&order=desc&exchange=CN&stockType={2}&column=symbol%2Cname%2Ccurrent%2Cchg%2Cpercent%2Clast_close%2Copen%2Chigh%2Clow%2Cvolume%2Camount%2Cmarket_capital%2Cpe_ttm%2Chigh52w%2Clow52w%2Chasexist&orderBy=percent"; 49 | // private static String XUEQIU_SZA = 50 | // "https://xueqiu.com/stock/quote_order.json?page={0}&size={1}&order=desc&exchange=CN&stockType=sza&column=symbol%2Cname%2Ccurrent%2Cchg%2Cpercent%2Clast_close%2Copen%2Chigh%2Clow%2Cvolume%2Camount%2Cmarket_capital%2Cpe_ttm%2Chigh52w%2Clow52w%2Chasexist&orderBy=percent"; 51 | 52 | private static String[] STOCK_TYPE = { "sha", "sza" }; 53 | 54 | private static int PAGE_SIZE = 50; 55 | private static int PAGE_COUNT = 50; 56 | 57 | private static String SOURCE_ENCODE = "utf-8"; 58 | private static String OUTPUT_ENCODE = "utf-8"; 59 | 60 | private static Logger logger = Logger.getLogger(XueqiuHqDataRobot.class); 61 | 62 | private static SqlSessionFactory sqlSessionFactory = null; 63 | 64 | static { 65 | // SqlSessionFactory sessionFactory = null; 66 | String resource = "mybatis-config.xml"; 67 | try { 68 | sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource)); 69 | } catch (IOException e) { 70 | logger.error("mybatis config error", e); 71 | throw new RuntimeException("mybatis config error", e); 72 | } 73 | } 74 | 75 | private static void updateXueqiuStock() { 76 | 77 | SqlSession sqlSession = null; 78 | 79 | try { 80 | 81 | sqlSession = sqlSessionFactory.openSession(true); 82 | 83 | TruncateTableMapper truncateTableMapper = sqlSession.getMapper(TruncateTableMapper.class); 84 | 85 | truncateTableMapper.truncateTable("xueqiu_stock"); 86 | 87 | XueqiuStockMapper xqStockMapper = sqlSession.getMapper(XueqiuStockMapper.class); 88 | 89 | for (String stockType : STOCK_TYPE) { 90 | for (int p = 1; p <= PAGE_COUNT; p++) { 91 | String requestUrl = MessageFormat.format(XUEQIU_HQ, p, PAGE_SIZE, stockType); 92 | 93 | HttpUtil httpUtil = new HttpUtil(); 94 | httpUtil.setRequestUrl(requestUrl); 95 | String response = httpUtil.doGet2(); 96 | 97 | JSONObject jsonObj = JSON.parseObject(response); 98 | 99 | JSONArray stocks = jsonObj.getJSONArray("data"); 100 | 101 | if (stocks.size() == 0) { 102 | logger.info(stockType + " hq data download finished"); 103 | break; 104 | } 105 | 106 | for (int i = 0; i < stocks.size(); i++) { 107 | // XueqiuStock xqStock = stocks.getObject(i, 108 | // XueqiuStock.class); 109 | JSONArray hq = stocks.getJSONArray(i); 110 | 111 | String symbol = hq.getString(0); 112 | String name = hq.getString(1); 113 | 114 | XueqiuStock xqStock = new XueqiuStock(); 115 | xqStock.setSymbol(symbol); 116 | xqStock.setName(name); 117 | 118 | xqStockMapper.insert(xqStock); 119 | 120 | // sqlSession.commit(); 121 | 122 | } 123 | 124 | } 125 | 126 | } 127 | 128 | } catch (Exception e) { 129 | logger.error("updateXueqiuStock出错", e); 130 | } finally { 131 | sqlSession.close(); 132 | } 133 | } 134 | 135 | public static void main(String[] args) { 136 | 137 | updateXueqiuStock(); 138 | } 139 | 140 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/expr/ExpressRunnerFactory.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.expr; 2 | 3 | import com.diffwind.expr.function.MAFunction; 4 | import com.diffwind.expr.function.MAXFunction; 5 | import com.diffwind.expr.function.MEANFunction; 6 | import com.diffwind.expr.function.MINFunction; 7 | import com.diffwind.expr.function.RANGEFunction; 8 | import com.diffwind.expr.function.SUMFunction; 9 | import com.diffwind.expr.function.WHICHFunction; 10 | import com.diffwind.expr.operator.AnyGTEOperator; 11 | import com.diffwind.expr.operator.AnyGTOperator; 12 | import com.diffwind.expr.operator.AnyLTEOperator; 13 | import com.diffwind.expr.operator.AnyLTOperator; 14 | import com.diffwind.expr.operator.EachGTEOperator; 15 | import com.diffwind.expr.operator.EachGTOperator; 16 | import com.diffwind.expr.operator.EachLTEOperator; 17 | import com.diffwind.expr.operator.EachLTOperator; 18 | import com.diffwind.expr.operator.GTEOperator; 19 | import com.diffwind.expr.operator.GTOperator; 20 | import com.diffwind.expr.operator.LTEOperator; 21 | import com.diffwind.expr.operator.LTOperator; 22 | import com.ql.util.express.ExpressRunner; 23 | 24 | public class ExpressRunnerFactory { 25 | 26 | public static ExpressRunner getInstance() { 27 | 28 | try { 29 | ExpressRunner runner = new ExpressRunner(); 30 | // 自定义运算符 31 | runner.addOperator("EACHGT", new EachGTOperator()); 32 | runner.addOperator("EACHGTE", new EachGTEOperator()); 33 | runner.addOperator("EACHLT", new EachLTOperator()); 34 | runner.addOperator("EACHLTE", new EachLTEOperator()); 35 | 36 | runner.addOperator("ANYGT", new AnyGTOperator()); 37 | runner.addOperator("ANYGTE", new AnyGTEOperator()); 38 | runner.addOperator("ANYLT", new AnyLTOperator()); 39 | runner.addOperator("ANYLTE", new AnyLTEOperator()); 40 | 41 | runner.addOperator("GT", new GTOperator()); 42 | runner.addOperator("GTE", new GTEOperator()); 43 | runner.addOperator("LT", new LTOperator()); 44 | runner.addOperator("LTE", new LTEOperator()); 45 | 46 | // 自定义函数 47 | runner.addFunction("MIN", new MINFunction()); 48 | runner.addFunction("MAX", new MAXFunction()); 49 | runner.addFunction("SUM", new SUMFunction()); 50 | runner.addFunction("MEAN", new MEANFunction()); 51 | runner.addFunction("RANGE", new RANGEFunction()); 52 | runner.addFunction("WHICH", new WHICHFunction()); 53 | runner.addFunction("MA", new MAFunction()); 54 | 55 | return runner; 56 | } catch (Exception e) { 57 | throw new RuntimeException("严重错误: 初始化ExpressRunner失败", e); 58 | } 59 | 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/expr/function/MAFunction.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.expr.function; 2 | 3 | import java.util.Arrays; 4 | 5 | import com.ql.util.express.Operator; 6 | 7 | public class MAFunction extends Operator{ 8 | 9 | public Object executeInner(Object[] list) throws Exception { 10 | if (!list[0].getClass().isArray() || list.length != 2){ 11 | throw new Exception("操作数异常, 正确的语法: MA(Double[] ts,int w)"); 12 | } 13 | 14 | Double[] ts = (Double[])list[0]; 15 | Integer w = (Integer)list[1]; 16 | if (w > ts.length) { 17 | throw new Exception(String.format("操作数异常: w超出数组范围(ts.length=%s,w=%s): MA(Double[] ts,int w)",ts.length,w)); 18 | } 19 | 20 | Double[] ma = Arrays.copyOf(ts, ts.length); 21 | Double sum = 0d; 22 | for (int i = 0; i < w; i++) sum += ts[i]; 23 | 24 | ma[0] = sum/w; 25 | for (int i = 0; i < (ts.length - w); i++) { 26 | //数据缺失 27 | if (ts[i+w] == null || Double.isNaN((ts[i+w])) ) 28 | break; 29 | 30 | sum = sum - ts[i] + ts[i+w]; 31 | ma[i+1] = sum/w; 32 | } 33 | 34 | return ma; 35 | 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/expr/function/MAXFunction.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.expr.function; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | 8 | import com.ql.util.express.Operator; 9 | 10 | public class MAXFunction extends Operator{ 11 | 12 | public Object executeInner(Object[] list) throws Exception { 13 | if (list.length == 0){ 14 | throw new Exception("操作数异常"); 15 | } 16 | 17 | List newlist = new ArrayList(); 18 | for (int i = 0; i < list.length; i++) { 19 | if (list[i].getClass().isArray()) { 20 | newlist.addAll(Arrays.asList((Object[])list[i])); 21 | } else { 22 | newlist.add(list[i]); 23 | } 24 | } 25 | 26 | Iterator iter = newlist.iterator(); 27 | Object result = iter.next(); 28 | while (iter.hasNext()) { 29 | Object i = iter.next(); 30 | if (((Number)i).doubleValue() > ((Number)result).doubleValue()) { 31 | result = i; 32 | } 33 | } 34 | return result; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/expr/function/MEANFunction.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.expr.function; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | 8 | import com.ql.util.express.Operator; 9 | 10 | public class MEANFunction extends Operator{ 11 | 12 | public Object executeInner(Object[] list) throws Exception { 13 | if (list.length == 0){ 14 | throw new Exception("操作数异常"); 15 | } 16 | 17 | List newlist = new ArrayList(); 18 | for (int i = 0; i < list.length; i++) { 19 | if (list[i].getClass().isArray()) { 20 | newlist.addAll(Arrays.asList((Object[])list[i])); 21 | } else { 22 | newlist.add(list[i]); 23 | } 24 | } 25 | 26 | Number result = 0; 27 | Iterator iter = newlist.iterator(); 28 | while (iter.hasNext()) { 29 | result = result.doubleValue() + ((Number)iter.next()).doubleValue(); 30 | } 31 | return result.doubleValue()/newlist.size(); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/expr/function/MINFunction.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.expr.function; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | 8 | import com.ql.util.express.Operator; 9 | 10 | public class MINFunction extends Operator{ 11 | 12 | public Object executeInner(Object[] list) throws Exception { 13 | if (list.length == 0){ 14 | throw new Exception("操作数异常"); 15 | } 16 | 17 | List newlist = new ArrayList(); 18 | for (int i = 0; i < list.length; i++) { 19 | if (list[i].getClass().isArray()) { 20 | newlist.addAll(Arrays.asList((Object[])list[i])); 21 | } else { 22 | newlist.add(list[i]); 23 | } 24 | } 25 | 26 | Iterator iter = newlist.iterator(); 27 | Object result = iter.next(); 28 | while (iter.hasNext()) { 29 | Object i = iter.next(); 30 | if (((Number)i).doubleValue() < ((Number)result).doubleValue()) { 31 | result = i; 32 | } 33 | } 34 | return result; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/expr/function/RANGEFunction.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.expr.function; 2 | 3 | import java.util.Arrays; 4 | 5 | import com.ql.util.express.Operator; 6 | 7 | public class RANGEFunction extends Operator{ 8 | 9 | public Object executeInner(Object[] list) throws Exception { 10 | if (!list[0].getClass().isArray() || (list.length != 2 && list.length != 3)){ 11 | throw new Exception("操作数异常, 正确的语法: RANGE(Object[] arr,int length) 或 RANGE(Object[] arr, int startIndex, int length)"); 12 | } 13 | 14 | Object[] arr = (Object[])list[0]; 15 | if (list.length == 2) { 16 | Integer length = (Integer)list[1]; 17 | if (length > arr.length) { 18 | throw new Exception(String.format("操作数异常: length超出数组范围(arr.length=%s,length=%s): RANGE(Object[] arr,int length)",arr.length,length)); 19 | } 20 | return Arrays.copyOfRange(arr, 0, length); 21 | } 22 | 23 | //startIndex从1开始 24 | if (list.length == 3) { 25 | Integer startIndex = (Integer)list[1] - 1; 26 | Integer length = (Integer)list[2]; 27 | if (startIndex + length > arr.length) { 28 | throw new Exception(String.format("操作数异常: length超出数组范围(arr.length=%s,startIndex=%s,length=%s): RANGE(Object[] arr, int startIndex, int length)",arr.length,startIndex,length)); 29 | } 30 | return Arrays.copyOfRange(arr, startIndex, startIndex+length); 31 | } 32 | 33 | throw new Exception("操作数异常, 正确的语法: RANGE(Object[] arr,int length) 或 RANGE(Object[] arr, int startIndex, int length)"); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/expr/function/SUMFunction.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.expr.function; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | 8 | import com.ql.util.express.Operator; 9 | 10 | public class SUMFunction extends Operator{ 11 | 12 | public Object executeInner(Object[] list) throws Exception { 13 | if (list.length == 0){ 14 | throw new Exception("操作数异常"); 15 | } 16 | 17 | List newlist = new ArrayList(); 18 | for (int i = 0; i < list.length; i++) { 19 | if (list[i].getClass().isArray()) { 20 | newlist.addAll(Arrays.asList((Object[])list[i])); 21 | } else { 22 | newlist.add(list[i]); 23 | } 24 | } 25 | 26 | Number result = 0; 27 | Iterator iter = newlist.iterator(); 28 | while (iter.hasNext()) { 29 | Object i = iter.next(); 30 | if (i instanceof Boolean) { 31 | result = result.doubleValue() + (((Boolean)i)? 1 : 0); 32 | } else { 33 | result = result.doubleValue() + ((Number)i).doubleValue(); 34 | } 35 | 36 | } 37 | return result; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/expr/function/WHICHFunction.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.expr.function; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | 8 | import com.ql.util.express.Operator; 9 | 10 | public class WHICHFunction extends Operator{ 11 | 12 | public Object executeInner(Object[] list) throws Exception { 13 | if (list.length == 0){ 14 | throw new Exception("操作数异常"); 15 | } 16 | 17 | List newlist = new ArrayList(); 18 | for (int i = 0; i < list.length; i++) { 19 | if (list[i].getClass().isArray()) { 20 | newlist.addAll(Arrays.asList((Object[])list[i])); 21 | } else { 22 | newlist.add(list[i]); 23 | } 24 | } 25 | 26 | int index = 0; 27 | Iterator iter = newlist.iterator(); 28 | while (iter.hasNext()) { 29 | index++; 30 | Object i = iter.next(); 31 | if ((Boolean)i ) { 32 | break; 33 | } 34 | } 35 | return index; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/expr/operator/AnyGTEOperator.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.expr.operator; 2 | 3 | import com.ql.util.express.Operator; 4 | 5 | public class AnyGTEOperator extends Operator{ 6 | 7 | public Object executeInner(Object[] list) throws Exception { 8 | Object[] a = (Object[])list[0]; 9 | Object b = (Object)list[1]; 10 | for (int i = 0; i < a.length; i++) { 11 | if (((Number)a[i]).doubleValue() >= ((Number)b).doubleValue()) { 12 | return true; 13 | } 14 | } 15 | 16 | return false; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/expr/operator/AnyGTOperator.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.expr.operator; 2 | 3 | import com.ql.util.express.Operator; 4 | 5 | public class AnyGTOperator extends Operator{ 6 | 7 | public Object executeInner(Object[] list) throws Exception { 8 | Object[] a = (Object[])list[0]; 9 | Object b = (Object)list[1]; 10 | for (int i = 0; i < a.length; i++) { 11 | if (((Number)a[i]).doubleValue() > ((Number)b).doubleValue()) { 12 | return true; 13 | } 14 | } 15 | 16 | return false; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/expr/operator/AnyLTEOperator.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.expr.operator; 2 | 3 | import com.ql.util.express.Operator; 4 | 5 | public class AnyLTEOperator extends Operator{ 6 | 7 | public Object executeInner(Object[] list) throws Exception { 8 | Object[] a = (Object[])list[0]; 9 | Object b = (Object)list[1]; 10 | for (int i = 0; i < a.length; i++) { 11 | if (((Number)a[i]).doubleValue() <= ((Number)b).doubleValue()) { 12 | return true; 13 | } 14 | } 15 | 16 | return false; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/expr/operator/AnyLTOperator.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.expr.operator; 2 | 3 | import com.ql.util.express.Operator; 4 | 5 | public class AnyLTOperator extends Operator{ 6 | 7 | public Object executeInner(Object[] list) throws Exception { 8 | Object[] a = (Object[])list[0]; 9 | Object b = (Object)list[1]; 10 | for (int i = 0; i < a.length; i++) { 11 | if (((Number)a[i]).doubleValue() < ((Number)b).doubleValue()) { 12 | return true; 13 | } 14 | } 15 | 16 | return false; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/expr/operator/EachGTEOperator.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.expr.operator; 2 | 3 | import com.ql.util.express.Operator; 4 | 5 | public class EachGTEOperator extends Operator{ 6 | 7 | public Object executeInner(Object[] list) throws Exception { 8 | Object[] a = (Object[])list[0]; 9 | Object b = (Object)list[1]; 10 | for (int i = 0; i < a.length; i++) { 11 | if (((Number)a[i]).doubleValue() < ((Number)b).doubleValue()) { 12 | return false; 13 | } 14 | } 15 | 16 | return true; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/expr/operator/EachGTOperator.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.expr.operator; 2 | 3 | import com.ql.util.express.Operator; 4 | 5 | public class EachGTOperator extends Operator{ 6 | 7 | public Object executeInner(Object[] list) throws Exception { 8 | Object[] a = (Object[])list[0]; 9 | Object b = (Object)list[1]; 10 | for (int i = 0; i < a.length; i++) { 11 | if (((Number)a[i]).doubleValue() <= ((Number)b).doubleValue()) { 12 | return false; 13 | } 14 | } 15 | 16 | return true; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/expr/operator/EachLTEOperator.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.expr.operator; 2 | 3 | import com.ql.util.express.Operator; 4 | 5 | public class EachLTEOperator extends Operator{ 6 | 7 | public Object executeInner(Object[] list) throws Exception { 8 | Object[] a = (Object[])list[0]; 9 | Object b = (Object)list[1]; 10 | for (int i = 0; i < a.length; i++) { 11 | if (((Number)a[i]).doubleValue() > ((Number)b).doubleValue()) { 12 | return false; 13 | } 14 | } 15 | 16 | return true; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/expr/operator/EachLTOperator.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.expr.operator; 2 | 3 | import com.ql.util.express.Operator; 4 | 5 | public class EachLTOperator extends Operator{ 6 | 7 | public Object executeInner(Object[] list) throws Exception { 8 | Object[] a = (Object[])list[0]; 9 | Object b = (Object)list[1]; 10 | for (int i = 0; i < a.length; i++) { 11 | if (((Number)a[i]).doubleValue() >= ((Number)b).doubleValue()) { 12 | return false; 13 | } 14 | } 15 | 16 | return true; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/expr/operator/GTEOperator.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.expr.operator; 2 | 3 | import com.ql.util.express.Operator; 4 | 5 | public class GTEOperator extends Operator{ 6 | 7 | public Object executeInner(Object[] list) throws Exception { 8 | boolean aIsArray = false, bIsArray = false; 9 | Object[] a = null, b = null; 10 | if (list[0].getClass().isArray()) { 11 | aIsArray = true; 12 | a = (Object[])list[0]; 13 | } else { 14 | a = new Object[]{list[0]}; 15 | } 16 | 17 | if (list[1].getClass().isArray()) { 18 | bIsArray = true; 19 | b = (Object[])list[1]; 20 | } else { 21 | b = new Object[]{list[1]}; 22 | } 23 | 24 | if (!aIsArray && !bIsArray) { 25 | boolean result = false; 26 | if (((Number)a[0]).doubleValue() >= ((Number)b[0]).doubleValue()) { 27 | result = true; 28 | } 29 | return result; 30 | } 31 | 32 | if (aIsArray && bIsArray) { 33 | if (a.length != b.length) 34 | throw new Exception("操作数长度不一致"); 35 | 36 | Boolean[] result = new Boolean[a.length]; 37 | for (int i = 0; i < a.length; i++) { 38 | if (((Number)a[i]).doubleValue() >= ((Number)b[i]).doubleValue()) { 39 | result[i] = true; 40 | } else { 41 | result[i] = false; 42 | } 43 | } 44 | return result; 45 | } 46 | 47 | if (aIsArray) { 48 | Boolean[] result = new Boolean[a.length]; 49 | for (int i = 0; i < a.length; i++) { 50 | if (((Number)a[i]).doubleValue() >= ((Number)b[0]).doubleValue()) { 51 | result[i] = true; 52 | } else { 53 | result[i] = false; 54 | } 55 | } 56 | return result; 57 | } 58 | 59 | if (bIsArray) { 60 | Boolean[] result = new Boolean[b.length]; 61 | for (int i = 0; i < b.length; i++) { 62 | if (((Number)a[0]).doubleValue() >= ((Number)b[i]).doubleValue()) { 63 | result[i] = true; 64 | } else { 65 | result[i] = false; 66 | } 67 | } 68 | return result; 69 | } 70 | 71 | return null; 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/expr/operator/GTOperator.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.expr.operator; 2 | 3 | import com.ql.util.express.Operator; 4 | 5 | public class GTOperator extends Operator{ 6 | 7 | public Object executeInner(Object[] list) throws Exception { 8 | boolean aIsArray = false, bIsArray = false; 9 | Object[] a = null, b = null; 10 | if (list[0].getClass().isArray()) { 11 | aIsArray = true; 12 | a = (Object[])list[0]; 13 | } else { 14 | a = new Object[]{list[0]}; 15 | } 16 | 17 | if (list[1].getClass().isArray()) { 18 | bIsArray = true; 19 | b = (Object[])list[1]; 20 | } else { 21 | b = new Object[]{list[1]}; 22 | } 23 | 24 | if (!aIsArray && !bIsArray) { 25 | boolean result = false; 26 | if (((Number)a[0]).doubleValue() > ((Number)b[0]).doubleValue()) { 27 | result = true; 28 | } 29 | return result; 30 | } 31 | 32 | if (aIsArray && bIsArray) { 33 | if (a.length != b.length) 34 | throw new Exception("操作数长度不一致"); 35 | 36 | Boolean[] result = new Boolean[a.length]; 37 | for (int i = 0; i < a.length; i++) { 38 | if (((Number)a[i]).doubleValue() > ((Number)b[i]).doubleValue()) { 39 | result[i] = true; 40 | } else { 41 | result[i] = false; 42 | } 43 | } 44 | return result; 45 | } 46 | 47 | if (aIsArray) { 48 | Boolean[] result = new Boolean[a.length]; 49 | for (int i = 0; i < a.length; i++) { 50 | if (((Number)a[i]).doubleValue() > ((Number)b[0]).doubleValue()) { 51 | result[i] = true; 52 | } else { 53 | result[i] = false; 54 | } 55 | } 56 | return result; 57 | } 58 | 59 | if (bIsArray) { 60 | Boolean[] result = new Boolean[b.length]; 61 | for (int i = 0; i < b.length; i++) { 62 | if (((Number)a[0]).doubleValue() > ((Number)b[i]).doubleValue()) { 63 | result[i] = true; 64 | } else { 65 | result[i] = false; 66 | } 67 | } 68 | return result; 69 | } 70 | 71 | return null; 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/expr/operator/LTEOperator.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.expr.operator; 2 | 3 | import com.ql.util.express.Operator; 4 | 5 | public class LTEOperator extends Operator{ 6 | 7 | public Object executeInner(Object[] list) throws Exception { 8 | boolean aIsArray = false, bIsArray = false; 9 | Object[] a = null, b = null; 10 | if (list[0].getClass().isArray()) { 11 | aIsArray = true; 12 | a = (Object[])list[0]; 13 | } else { 14 | a = new Object[]{list[0]}; 15 | } 16 | 17 | if (list[1].getClass().isArray()) { 18 | bIsArray = true; 19 | b = (Object[])list[1]; 20 | } else { 21 | b = new Object[]{list[1]}; 22 | } 23 | 24 | if (!aIsArray && !bIsArray) { 25 | boolean result = false; 26 | if (((Number)a[0]).doubleValue() <= ((Number)b[0]).doubleValue()) { 27 | result = true; 28 | } 29 | return result; 30 | } 31 | 32 | if (aIsArray && bIsArray) { 33 | if (a.length != b.length) 34 | throw new Exception("操作数长度不一致"); 35 | 36 | Boolean[] result = new Boolean[a.length]; 37 | for (int i = 0; i < a.length; i++) { 38 | if (((Number)a[i]).doubleValue() <= ((Number)b[i]).doubleValue()) { 39 | result[i] = true; 40 | } else { 41 | result[i] = false; 42 | } 43 | } 44 | return result; 45 | } 46 | 47 | if (aIsArray) { 48 | Boolean[] result = new Boolean[a.length]; 49 | for (int i = 0; i < a.length; i++) { 50 | if (((Number)a[i]).doubleValue() <= ((Number)b[0]).doubleValue()) { 51 | result[i] = true; 52 | } else { 53 | result[i] = false; 54 | } 55 | } 56 | return result; 57 | } 58 | 59 | if (bIsArray) { 60 | Boolean[] result = new Boolean[b.length]; 61 | for (int i = 0; i < b.length; i++) { 62 | if (((Number)a[0]).doubleValue() <= ((Number)b[i]).doubleValue()) { 63 | result[i] = true; 64 | } else { 65 | result[i] = false; 66 | } 67 | } 68 | return result; 69 | } 70 | 71 | return null; 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/expr/operator/LTOperator.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.expr.operator; 2 | 3 | import com.ql.util.express.Operator; 4 | 5 | public class LTOperator extends Operator{ 6 | 7 | public Object executeInner(Object[] list) throws Exception { 8 | boolean aIsArray = false, bIsArray = false; 9 | Object[] a = null, b = null; 10 | if (list[0].getClass().isArray()) { 11 | aIsArray = true; 12 | a = (Object[])list[0]; 13 | } else { 14 | a = new Object[]{list[0]}; 15 | } 16 | 17 | if (list[1].getClass().isArray()) { 18 | bIsArray = true; 19 | b = (Object[])list[1]; 20 | } else { 21 | b = new Object[]{list[1]}; 22 | } 23 | 24 | if (!aIsArray && !bIsArray) { 25 | boolean result = false; 26 | if (((Number)a[0]).doubleValue() < ((Number)b[0]).doubleValue()) { 27 | result = true; 28 | } 29 | return result; 30 | } 31 | 32 | if (aIsArray && bIsArray) { 33 | if (a.length != b.length) 34 | throw new Exception("操作数长度不一致"); 35 | 36 | Boolean[] result = new Boolean[a.length]; 37 | for (int i = 0; i < a.length; i++) { 38 | if (((Number)a[i]).doubleValue() < ((Number)b[i]).doubleValue()) { 39 | result[i] = true; 40 | } else { 41 | result[i] = false; 42 | } 43 | } 44 | return result; 45 | } 46 | 47 | if (aIsArray) { 48 | Boolean[] result = new Boolean[a.length]; 49 | for (int i = 0; i < a.length; i++) { 50 | if (((Number)a[i]).doubleValue() < ((Number)b[0]).doubleValue()) { 51 | result[i] = true; 52 | } else { 53 | result[i] = false; 54 | } 55 | } 56 | return result; 57 | } 58 | 59 | if (bIsArray) { 60 | Boolean[] result = new Boolean[b.length]; 61 | for (int i = 0; i < b.length; i++) { 62 | if (((Number)a[0]).doubleValue() < ((Number)b[i]).doubleValue()) { 63 | result[i] = true; 64 | } else { 65 | result[i] = false; 66 | } 67 | } 68 | return result; 69 | } 70 | 71 | return null; 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/main/DiffWindFirstTime.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.main; 2 | 3 | import org.apache.log4j.Logger; 4 | 5 | import com.diffwind.data.SinaHangyeDataRobot; 6 | import com.diffwind.data.TdxDataDecoder; 7 | //import com.diffwind.data.XueqiuStockFinancialStatementRobot; 8 | import com.diffwind.data.XueqiuStockFinanceDataRobot; 9 | import com.diffwind.data.XueqiuStockShareschgDataRobot; 10 | import com.diffwind.stats.DataHandler; 11 | 12 | /** 13 | * DiffWind初次执行时需准备历史数据,初始化数据库 14 | * [通达信]日线数据说明: 15 | * 作者使用的通达信软件客户端为Windows版本"招商证券-智远理财"客户端,通过"数据管理 > 盘后数据下载"下载日线数据。 16 | * 日线数据的存储路经为:C:/zd_zszq/vipdoc/ (C:/zd_zszq为软件安装路径) 17 | * 18 | * @author billberg 19 | * 20 | */ 21 | public class DiffWindFirstTime { 22 | 23 | private static Logger logger = Logger.getLogger(DataHandler.class); 24 | 25 | public static void main(String[] args) { 26 | 27 | logger.info("-------- 准备历史数据开始 --------"); 28 | 29 | //股票最新列表,名字或许更新,如st 30 | //[新浪]股票行业分类(全量,按月更新) 31 | SinaHangyeDataRobot.updateSinaZjhhangye(); 32 | 33 | //[雪球]主要财务指标历史数据(全量,下载20年数据) 34 | XueqiuStockFinanceDataRobot.downloadFinanceData(false); 35 | //[雪球]股本结构历史数据(全量,下载20年数据) 36 | XueqiuStockShareschgDataRobot.downloadShareschgData(false); 37 | //[雪球]财务报表历史数据(全量) 38 | //XueqiuStockFinancialStatementRobot.downloadIncomeStatementData(false); 39 | 40 | //[通达信]日线数据(全量,导入通达信盘后数据下载[2001-2015] 15年历史数据) 41 | TdxDataDecoder.start(2001, 2005); 42 | TdxDataDecoder.start(2006, 2010); 43 | TdxDataDecoder.start(2011, 2015); 44 | 45 | logger.info("-------- 准备历史数据结束 --------"); 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/main/DiffWindMain.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.main; 2 | 3 | import org.apache.log4j.Logger; 4 | 5 | import com.diffwind.data.SinaHangyeDataRobot; 6 | import com.diffwind.data.TdxDataDecoder; 7 | import com.diffwind.data.XueqiuStockFinancialStatementRobot; 8 | import com.diffwind.data.XueqiuStockFinanceDataRobot; 9 | import com.diffwind.data.XueqiuStockShareschgDataRobot; 10 | import com.diffwind.stats.DataHandler; 11 | import com.diffwind.stats.filters.MingxingCasesFilter; 12 | 13 | /** 14 | * 执行筛选模型,筛选规则参考{@link FilterRules} 15 | * 16 | * @author zhangjz 17 | * 18 | */ 19 | public class DiffWindMain { 20 | 21 | private static Logger logger = Logger.getLogger(DataHandler.class); 22 | 23 | public static void main(String[] args) { 24 | 25 | logger.info("-------- 数据处理开始 --------"); 26 | 27 | //股票最新列表,名字或许更新,如st 28 | //[新浪]股票行业分类(全量,按月更新-可选) 29 | //SinaHangyeDataRobot.updateSinaZjhhangye(); 30 | 31 | //[雪球]主要财务指标历史数据(增量,按月更新) 32 | XueqiuStockFinanceDataRobot.downloadFinanceData(true); 33 | //[雪球]股本结构历史数据(增量,按月更新) 34 | XueqiuStockShareschgDataRobot.downloadShareschgData(true); 35 | //[雪球]财务报表历史数据(全量) 36 | XueqiuStockFinancialStatementRobot.downloadIncomeStatementData(false); 37 | 38 | //[通达信]日线数据(增量,分区表,按日更新最近5年) 39 | TdxDataDecoder.start(2016,2020); 40 | 41 | 42 | logger.info("-------- 数据处理结束 --------"); 43 | 44 | logger.info("-------- 筛选开始 -------- "); 45 | 46 | //10年统计筛选 47 | MingxingCasesFilter.filterByY(10, true); 48 | //5年统计筛选 49 | MingxingCasesFilter.filterByY(5, true); 50 | 51 | logger.info("-------- 筛选结束 -------- "); 52 | 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/stats/DataHandler.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.stats; 2 | 3 | import org.apache.log4j.Logger; 4 | 5 | import com.diffwind.data.SinaHangyeDataRobot; 6 | import com.diffwind.data.TdxDataDecoder; 7 | import com.diffwind.data.XueqiuStockFinancialStatementRobot; 8 | import com.diffwind.data.XueqiuStockFinanceDataRobot; 9 | import com.diffwind.data.XueqiuStockShareschgDataRobot; 10 | 11 | /** 12 | * 数据处理 13 | * 数据更新尽量改成增量,必要时使用分区表存历史数据 14 | */ 15 | public class DataHandler { 16 | 17 | private static Logger logger = Logger.getLogger(DataHandler.class); 18 | 19 | public static void main(String[] args) { 20 | 21 | logger.info("-------- 数据处理开始 --------"); 22 | 23 | //股票最新列表,名字或许更新,如st 24 | //[新浪]股票行业分类(全量,按月更新) 25 | SinaHangyeDataRobot.updateSinaZjhhangye(); 26 | 27 | //[雪球]主要财务指标历史数据(增量,按月更新) 28 | XueqiuStockFinanceDataRobot.downloadFinanceData(true); 29 | //[雪球]股本结构历史数据(增量,按月更新) 30 | XueqiuStockShareschgDataRobot.downloadShareschgData(true); 31 | //[雪球]财务报表历史数据 32 | XueqiuStockFinancialStatementRobot.downloadIncomeStatementData(false); 33 | 34 | //[通达信]日线数据(增量,分区表,按日更新最近5年) 35 | TdxDataDecoder.start(2016,2020); 36 | 37 | 38 | logger.info("-------- 数据处理结束 --------"); 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/stats/R/.Rapp.history: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/billberg/DiffWind/4f9afe56e7371e24cfa489f11e8869cc3789f5cf/src/main/java/com/diffwind/stats/R/.Rapp.history -------------------------------------------------------------------------------- /src/main/java/com/diffwind/stats/R/LongWindCasesAnalysis.R: -------------------------------------------------------------------------------- 1 | require(RPostgreSQL) 2 | # 读入driver 3 | drv = dbDriver("PostgreSQL") 4 | # 填写连接信息 5 | con = dbConnect(drv, dbname = "diffview", 6 | user = "diffview", password = "diffview", host="localhost", port = 5432) 7 | 8 | # 查询语句 9 | qry <- "select f1.* 10 | from xueqiu_stock_finance f1 11 | where f1.reportdate = make_date(extract(year from now())::int-1,12,31) 12 | and f1.netprofit > 0 13 | --and f1.netprofit < 100*1e8 14 | and f1.weightedroe > 0" 15 | 16 | qry <- "select f1.* 17 | from xueqiu_stock_day_fq f1 18 | where f1.symbol = 'sh600887' 19 | order by date desc" 20 | 21 | df = dbGetQuery(con, qry) 22 | 23 | 24 | # pe, roe 25 | plot(df$date,df$pe, type = 'l') 26 | 27 | # 融资融券 28 | scode = '000625' 29 | qry <- paste("select (e.rzrq_data->>'tdate')::date \"date\", e.rzrq_data->'rzrqyecz' \"rzrqyecz\", x.close 30 | from eastmoney_stock_rzrq_json e left join xueqiu_stock_day_fq x 31 | on (e.rzrq_data->>'scode' = substr(x.symbol,3) and (e.rzrq_data->>'tdate')::date = x.date) 32 | where rzrq_data->>'scode' = '", scode, "' 33 | order by rzrq_data->>'tdate' desc;", sep="") 34 | 35 | df = dbGetQuery(con, qry) 36 | 37 | markedDate <- as.Date(c('2017-12-31','2018-01-10')) 38 | # 39 | plot(df$date,df$close,type='l',col='gray',xaxt='n',xlab='',ylab='Close/Rzrq',family='STKaiti') 40 | axis.Date(1, at=seq(min(df$date), max(df$date), by='3 mon'), format='%Y/%m/%d',las=2,cex.axis=0.7) 41 | abline(v=seq(min(df$date), max(df$date), by='3 mon'), lty=3,col='gray') 42 | abline(v=markedDate, lty=3,col='orange') 43 | 44 | title(main=scode,family='STKaiti') 45 | par(new=T) 46 | #plot(df$date,df$rzrqyecz, type = 'l',xaxt='n',xlab='') 47 | plot(df$date,df$rzrqyecz,type='l',col='green',xaxt='n',xlab='',ylab='',axes=F) 48 | axis(side=2,lwd=0.7,lwd.ticks=0.7,tck=.01,cex.axis=0.7,mgp=c(0,-1,0),col='green',col.ticks='green',col.axis='green') 49 | 50 | # 输出绘图 51 | outputFileName <- "D:/Users/zhangjz/projects/DiffWind.output/stats.chart/汽车行业-sz000625长安汽车-w[500].png" 52 | #outputFileName <- "D:/Users/zhangjz/projects/DiffWind.output/stats.chart/000625.png" 53 | png(outputFileName,width=as.integer(length(df$date)/1000*800),height=800,res=160) 54 | plot(df$date,df$close,type='l',col='gray',xaxt='n',xlab='',ylab='Close/Rzrq',family='STKaiti') 55 | axis.Date(1, at=seq(min(df$date), max(df$date), by='3 mon'), format='%Y/%m/%d',las=2,cex.axis=0.7) 56 | abline(v=seq(min(df$date), max(df$date), by='3 mon'), lty=3,col='gray') 57 | abline(v=markedDate, lty=3,col='orange') 58 | 59 | title(main=scode,family='STKaiti') 60 | 61 | dev.off() #关闭当前绘图设备 62 | 63 | 64 | # 输出矢量图 65 | plot(df$date,df$close,type='l',col='gray',xaxt='n',xlab='',ylab='Close/Rzrq',family='STKaiti') 66 | axis.Date(1, at=seq(min(df$date), max(df$date), by='3 mon'), format='%Y/%m/%d',las=2,cex.axis=0.7) 67 | abline(v=seq(min(df$date), max(df$date), by='3 mon'), lty=3,col='gray') 68 | abline(v=markedDate, lty=3,col='orange') 69 | 70 | title(main=scode,family='STKaiti') 71 | # Mac R 3.2.1已不支持savePlot保存矢量图 72 | #savePlot("shiliang", type=c("eps"),device=dev.cur(),restoreConsole=TRUE) 73 | #savePlot("shiliang", type=c("eps"),device=dev.cur()) 74 | 75 | # 用pdf或postscript保存矢量图 76 | pdf(file="saving_plot4.pdf") 77 | postscript(file="/Users/zhangjz/projects/DiffWind.output/stats.chart/saving_plot4.ps") 78 | plot(df$date,df$close,type='l',col='gray',xaxt='n',xlab='',ylab='Close/Rzrq',family='STKaiti') 79 | axis.Date(1, at=seq(min(df$date), max(df$date), by='3 mon'), format='%Y/%m/%d',las=2,cex.axis=0.7) 80 | abline(v=seq(min(df$date), max(df$date), by='3 mon'), lty=3,col='gray') 81 | abline(v=markedDate, lty=3,col='orange') 82 | 83 | title(main=scode,family='STKaiti') 84 | dev.off() 85 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/stats/R/PGconn.R: -------------------------------------------------------------------------------- 1 | require(RPostgreSQL) 2 | # 读入driver 3 | drv = dbDriver("PostgreSQL") 4 | # 填写连接信息 5 | con = dbConnect(drv, dbname = "diffview", 6 | user = "diffview", password = "diffview", host="localhost", port = 5432) 7 | # 查询语句 8 | qry <- "select * 9 | from xueqiu_stock_finance s 10 | where s.symbol = 'SZ002230' 11 | order by reportdate desc;" 12 | rs = dbSendQuery(con, statement = qry) 13 | # 收割结果 14 | df = fetch(rs, n = -1) 15 | # 其实可以直接执行查询返回结果 16 | df = dbGetQuery(con, qry) 17 | plot(df$reportdate,df$netassgrowrate, type = 'l') 18 | # 断开连接 19 | dbDisconnect(con) 20 | # 释放资源 21 | dbUnloadDriver(drv) 22 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/stats/R/StkFinance.R: -------------------------------------------------------------------------------- 1 | require(RPostgreSQL) 2 | # 读入driver 3 | drv = dbDriver("PostgreSQL") 4 | # 填写连接信息 5 | con = dbConnect(drv, dbname = "diffview", 6 | user = "diffview", password = "diffview", host="localhost", port = 5432) 7 | # 查询语句 8 | symbol = 'SH600104' 9 | qry <- paste("select * 10 | from xueqiu_stock_finance s 11 | where s.symbol = '",symbol,"' 12 | order by reportdate desc;", sep="") 13 | 14 | df = dbGetQuery(con, qry) 15 | 16 | plot(df$reportdate,df$netassgrowrate, type = 'l') 17 | # 主营业务收入 18 | plot(df$reportdate,df$mainbusiincome, type = 'l') 19 | # 主营业务利润 20 | plot(df$reportdate,df$mainbusiprofit, type = 'l') 21 | # 利润总额 22 | plot(df$reportdate,df$totprofit, type = 'l') 23 | # 净利润 24 | plot(df$reportdate,df$netprofit, type = 'l') 25 | # 筹资活动产生的现金流量净额 26 | plot(df$reportdate,df$finnetcflow, type = 'l') 27 | # 股东权益合计 28 | plot(df$reportdate,df$totsharequi, type = 'l') 29 | 30 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/stats/StockDayView.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.stats; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | 6 | public class StockDayView { 7 | 8 | private String symbol; 9 | 10 | private Date date; 11 | 12 | private Double pb; 13 | 14 | private Double pe1Y; 15 | private Double pe4Q; 16 | private Double peExp; 17 | 18 | private Double MV2EBIT1Y; 19 | private Double MV2EBIT4Q; 20 | 21 | private Double zongshizhi; 22 | 23 | private Double liutongshizhi; 24 | 25 | // 26 | private Double close; 27 | 28 | //目前模型指标并未使用,该字段只用于图形拟合与相关性计算 29 | private Double fqClose; 30 | 31 | //季度报表 32 | private StockQuarterView quarterView; 33 | 34 | 35 | public String getSymbol() { 36 | return symbol; 37 | } 38 | 39 | public void setSymbol(String symbol) { 40 | this.symbol = symbol; 41 | } 42 | 43 | public Date getDate() { 44 | return date; 45 | } 46 | 47 | public void setDate(Date date) { 48 | this.date = date; 49 | } 50 | 51 | public Double getPb() { 52 | return pb; 53 | } 54 | 55 | public void setPb(Double pb) { 56 | this.pb = pb; 57 | } 58 | 59 | public Double getPe1Y() { 60 | return pe1Y; 61 | } 62 | 63 | public void setPe1Y(Double pe1y) { 64 | pe1Y = pe1y; 65 | } 66 | 67 | public Double getPe4Q() { 68 | return pe4Q; 69 | } 70 | 71 | public void setPe4Q(Double pe4q) { 72 | pe4Q = pe4q; 73 | } 74 | 75 | public Double getPeExp() { 76 | return peExp; 77 | } 78 | 79 | public void setPeExp(Double peExp) { 80 | this.peExp = peExp; 81 | } 82 | 83 | public Double getZongshizhi() { 84 | return zongshizhi; 85 | } 86 | 87 | public void setZongshizhi(Double zongshizhi) { 88 | this.zongshizhi = zongshizhi; 89 | } 90 | 91 | public Double getLiutongshizhi() { 92 | return liutongshizhi; 93 | } 94 | 95 | public void setLiutongshizhi(Double liutongshizhi) { 96 | this.liutongshizhi = liutongshizhi; 97 | } 98 | 99 | public Double getClose() { 100 | return close; 101 | } 102 | 103 | public void setClose(Double close) { 104 | this.close = close; 105 | } 106 | 107 | 108 | public Double getFqClose() { 109 | return fqClose; 110 | } 111 | 112 | public void setFqClose(Double fqClose) { 113 | this.fqClose = fqClose; 114 | } 115 | 116 | public StockQuarterView getQuarterView() { 117 | return quarterView; 118 | } 119 | 120 | public void setQuarterView(StockQuarterView quarterView) { 121 | this.quarterView = quarterView; 122 | } 123 | 124 | public Double getMV2EBIT1Y() { 125 | return MV2EBIT1Y; 126 | } 127 | 128 | public void setMV2EBIT1Y(Double mV2EBIT1Y) { 129 | MV2EBIT1Y = mV2EBIT1Y; 130 | } 131 | 132 | public Double getMV2EBIT4Q() { 133 | return MV2EBIT4Q; 134 | } 135 | 136 | public void setMV2EBIT4Q(Double mV2EBIT4Q) { 137 | MV2EBIT4Q = mV2EBIT4Q; 138 | } 139 | 140 | 141 | 142 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/stats/StockDayViewWind.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.stats; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Calendar; 5 | import java.util.Date; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | public class StockDayViewWind { 11 | 12 | public final String symbol; 13 | //(倒序)时间序列 14 | public final List dayViewHist = new ArrayList(); 15 | //public final Map lookupDate = new HashMap(); 16 | public final Map dateIndex = new HashMap(); 17 | 18 | //股本变更和财报历史记录 19 | public StockQuarterViewWind financeChgHistWind = null; 20 | 21 | public StockDayViewWind(String symbol) { 22 | this.symbol = symbol; 23 | } 24 | 25 | public void add(StockDayView dayView) { 26 | dayViewHist.add(dayView); 27 | dateIndex.put(dayView.getDate(), dayViewHist.size()-1); 28 | } 29 | 30 | public StockDayView at(Date d) { 31 | Integer index = dateIndex.get(d); 32 | return dayViewHist.get(index); 33 | } 34 | 35 | public int size() { 36 | return dayViewHist.size(); 37 | } 38 | 39 | //TODO: 提供该方法不好,待完善 40 | public StockDayView get(int i) { 41 | return dayViewHist.get(i); 42 | } 43 | 44 | /** 45 | * fromDate < toDate 46 | * @param fromDate 47 | * @param toDate 48 | * @return 49 | */ 50 | public List rangeOf(Date fromDate, Date toDate) { 51 | Integer fromIndex = -1, toIndex = -1; 52 | if (toDate.after(dayViewHist.get(0).getDate())) { 53 | fromIndex = 0; 54 | } 55 | if (fromDate.before(dayViewHist.get(dayViewHist.size()-1).getDate())) { 56 | toIndex = dayViewHist.size(); 57 | } 58 | 59 | if (toDate.before(dayViewHist.get(dayViewHist.size()-1).getDate()) 60 | || fromDate.after(dayViewHist.get(0).getDate()) 61 | || fromDate.after(toDate) ) { 62 | return null; 63 | } 64 | 65 | // 66 | Calendar cal = Calendar.getInstance(); 67 | cal.setTime(toDate); 68 | while (dateIndex.get(toDate) == null && toDate.after(fromDate)) { 69 | cal.add(Calendar.DAY_OF_MONTH, -1); 70 | toDate = cal.getTime(); 71 | } 72 | if (dateIndex.get(toDate) == null) { 73 | return null; 74 | } 75 | 76 | fromIndex = dateIndex.get(toDate); 77 | 78 | // 79 | cal.setTime(fromDate); 80 | while (dateIndex.get(fromDate) == null && fromDate.before(toDate)) { 81 | cal.add(Calendar.DAY_OF_MONTH, 1); 82 | fromDate = cal.getTime(); 83 | } 84 | if (dateIndex.get(fromDate) == null) { 85 | return null; 86 | } 87 | 88 | toIndex = dateIndex.get(fromDate) + 1; 89 | 90 | return dayViewHist.subList(fromIndex, toIndex); 91 | } 92 | 93 | 94 | public List rangeOf(int w) { 95 | if (w <= dayViewHist.size()) { 96 | return dayViewHist.subList(0, w); 97 | } else { 98 | return dayViewHist; 99 | } 100 | } 101 | 102 | 103 | 104 | /** 105 | * 时间序列的指标矩阵 106 | * @return 107 | */ 108 | public Double[][] toMatrix() { 109 | //每个指标一列,使用不是太方便 110 | Double[][] matrix = dayViewHist.stream().map(obj -> new Double[]{obj.getPb(),obj.getPe1Y()}).toArray(Double[][]::new); 111 | return matrix; 112 | 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/stats/StockQuarterView.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.stats; 2 | 3 | import java.util.Calendar; 4 | import java.util.Date; 5 | 6 | import com.diffwind.util.DateUtil; 7 | 8 | /** 9 | * TODO: EBIT 10 | * @author billberg 11 | * 12 | */ 13 | public class StockQuarterView { 14 | //类型: F-财报日, G-股本变更日, X-财报日且是股本变更日 15 | private char type = 'F'; 16 | 17 | private String symbol; 18 | 19 | //财报日 20 | private Date reportDate; 21 | //财报披露日 22 | @Deprecated 23 | private Date piluDate; 24 | 25 | //财报日的年、季度 26 | private int reportYear; 27 | private int reportQuarter; 28 | 29 | 30 | /******** 盈利指标 ********/ 31 | //主营业务收入 32 | private Double mainBizIncome = Double.NaN; 33 | 34 | //季报净利润 35 | private Double netprofit = Double.NaN; 36 | //季报EBIT粗估 37 | private Double EBIT = Double.NaN; 38 | //利润表科目-税金及附加 39 | private Double jingyingShui = Double.NaN; 40 | //利润表科目-所得税费用 41 | private Double suodeShui = Double.NaN; 42 | 43 | //上年净利润 44 | private Double netprofit1Y = Double.NaN; 45 | //上4个季度净利润 46 | private Double netprofit4Q = Double.NaN; 47 | //预期年净利润 48 | private Double netprofitExp = Double.NaN;// 与上年同期相比的年净利润估值 49 | 50 | // 上年ROE 51 | private Double weightedroe1Y = Double.NaN; 52 | //上4个季度ROE 53 | private Double weightedroe4Q = Double.NaN; 54 | //预期年ROE 55 | private Double weightedroeExp = Double.NaN;// 与上年同期相比的年净资产收益率估值 56 | 57 | //TODO 58 | //上年EBIT 59 | private Double EBIT1Y = Double.NaN; 60 | //上4个季度EBIT 61 | private Double EBIT4Q = Double.NaN; 62 | 63 | //股本 64 | private Double totalGuben = Double.NaN; 65 | 66 | //每股净资产=净资产/总股本 67 | private Double naps = Double.NaN; 68 | //每股收益=净利润/总股本 69 | //根据上年净利润计算 70 | private Double eps1Y = Double.NaN; 71 | //根据上4个季度净利润计算 72 | private Double eps4Q = Double.NaN; 73 | //根据预期年净利润计算 74 | private Double epsExp = Double.NaN; 75 | 76 | /******** 规模指标 ********/ 77 | //总资产 78 | private Double totalAssets = Double.NaN; 79 | //净资产 80 | private Double totalShareEquity = Double.NaN; 81 | 82 | /******** 成长指标 ********/ 83 | //净资产增长率(相比去年底) 84 | private Double netAssetsGrowthRate = Double.NaN; 85 | //总资产增长率(相比去年底) 86 | private Double totalAssetsGrowthRate = Double.NaN; 87 | //主营业务收入增长率(同比) 88 | private Double mainBizIncomeGrowthRate = Double.NaN; 89 | //净利润增长率(同比) 90 | 91 | /******** 股权结构 ********/ 92 | //TODO 总股本 93 | 94 | 95 | public String toString() { 96 | return String.format("{piluDate: %s, reportDate: %s, type: %s}", DateUtil.yyyyMMdd10.get().format(piluDate),DateUtil.yyyyMMdd10.get().format(reportDate), type); 97 | } 98 | 99 | public String getSymbol() { 100 | return symbol; 101 | } 102 | public void setSymbol(String symbol) { 103 | this.symbol = symbol; 104 | } 105 | public Date getReportDate() { 106 | return reportDate; 107 | } 108 | public void setReportDate(Date reportDate) { 109 | this.reportDate = reportDate; 110 | Calendar cal = Calendar.getInstance(); 111 | cal.setTime(reportDate); 112 | reportYear = cal.get(Calendar.YEAR); 113 | reportQuarter = (cal.get(Calendar.MONTH) + 1)/3; 114 | } 115 | public Double getNetprofit1Y() { 116 | return netprofit1Y; 117 | } 118 | public void setNetprofit1Y(Double netprofit1y) { 119 | netprofit1Y = netprofit1y; 120 | } 121 | public Double getNetprofit4Q() { 122 | return netprofit4Q; 123 | } 124 | public void setNetprofit4Q(Double netprofit4q) { 125 | netprofit4Q = netprofit4q; 126 | } 127 | public Double getNetprofitExp() { 128 | return netprofitExp; 129 | } 130 | public void setNetprofitExp(Double netprofitExp) { 131 | this.netprofitExp = netprofitExp; 132 | } 133 | public Double getWeightedroe1Y() { 134 | return weightedroe1Y; 135 | } 136 | public void setWeightedroe1Y(Double weightedroe1y) { 137 | weightedroe1Y = weightedroe1y; 138 | } 139 | public Double getWeightedroe4Q() { 140 | return weightedroe4Q; 141 | } 142 | public void setWeightedroe4Q(Double weightedroe4q) { 143 | weightedroe4Q = weightedroe4q; 144 | } 145 | public Double getWeightedroeExp() { 146 | return weightedroeExp; 147 | } 148 | public void setWeightedroeExp(Double weightedroeExp) { 149 | this.weightedroeExp = weightedroeExp; 150 | } 151 | public Double getNaps() { 152 | return naps; 153 | } 154 | public void setNaps(Double naps) { 155 | this.naps = naps; 156 | } 157 | public Double getEps1Y() { 158 | return eps1Y; 159 | } 160 | public void setEps1Y(Double eps1y) { 161 | eps1Y = eps1y; 162 | } 163 | public Double getEps4Q() { 164 | return eps4Q; 165 | } 166 | public void setEps4Q(Double eps4q) { 167 | eps4Q = eps4q; 168 | } 169 | public Double getEpsExp() { 170 | return epsExp; 171 | } 172 | public void setEpsExp(Double epsExp) { 173 | this.epsExp = epsExp; 174 | } 175 | public Double getTotalAssets() { 176 | return totalAssets; 177 | } 178 | public void setTotalAssets(Double totalAssets) { 179 | this.totalAssets = totalAssets; 180 | } 181 | public Double getNetAssetsGrowthRate() { 182 | return netAssetsGrowthRate; 183 | } 184 | public void setNetAssetsGrowthRate(Double netAssetsGrowthRate) { 185 | this.netAssetsGrowthRate = netAssetsGrowthRate; 186 | } 187 | public Double getTotalAssetsGrowthRate() { 188 | return totalAssetsGrowthRate; 189 | } 190 | public void setTotalAssetsGrowthRate(Double totalAssetsGrowthRate) { 191 | this.totalAssetsGrowthRate = totalAssetsGrowthRate; 192 | } 193 | @Deprecated 194 | public Date getPiluDate() { 195 | return piluDate; 196 | } 197 | @Deprecated 198 | public void setPiluDate(Date piluDate) { 199 | this.piluDate = piluDate; 200 | } 201 | public Double getTotalShareEquity() { 202 | return totalShareEquity; 203 | } 204 | public void setTotalShareEquity(Double totalShareEquity) { 205 | this.totalShareEquity = totalShareEquity; 206 | } 207 | public char getType() { 208 | return type; 209 | } 210 | public void setType(char type) { 211 | this.type = type; 212 | } 213 | 214 | public int getReportYear() { 215 | return reportYear; 216 | } 217 | 218 | public void setReportYear(int reportYear) { 219 | this.reportYear = reportYear; 220 | } 221 | 222 | public int getReportQuarter() { 223 | return reportQuarter; 224 | } 225 | 226 | public void setReportQuarter(int reportQuarter) { 227 | this.reportQuarter = reportQuarter; 228 | } 229 | 230 | public Double getNetprofit() { 231 | return netprofit; 232 | } 233 | 234 | public void setNetprofit(Double netprofit) { 235 | this.netprofit = netprofit; 236 | } 237 | 238 | public Double getEBIT() { 239 | return EBIT; 240 | } 241 | 242 | public void setEBIT(Double eBITDA) { 243 | EBIT = eBITDA; 244 | } 245 | 246 | public Double getMainBizIncomeGrowthRate() { 247 | return mainBizIncomeGrowthRate; 248 | } 249 | 250 | public void setMainBizIncomeGrowthRate(Double mainBizIncomeGrowthRate) { 251 | this.mainBizIncomeGrowthRate = mainBizIncomeGrowthRate; 252 | } 253 | 254 | public Double getEBIT1Y() { 255 | return EBIT1Y; 256 | } 257 | 258 | public void setEBIT1Y(Double eBITDA1Y) { 259 | EBIT1Y = eBITDA1Y; 260 | } 261 | 262 | public Double getEBIT4Q() { 263 | return EBIT4Q; 264 | } 265 | 266 | public void setEBIT4Q(Double eBITDA4Q) { 267 | EBIT4Q = eBITDA4Q; 268 | } 269 | 270 | public Double getTotalGuben() { 271 | return totalGuben; 272 | } 273 | 274 | public void setTotalGuben(Double totalGuben) { 275 | this.totalGuben = totalGuben; 276 | } 277 | 278 | public Double getJingyingShui() { 279 | return jingyingShui; 280 | } 281 | 282 | public void setJingyingShui(Double jingyingShui) { 283 | this.jingyingShui = jingyingShui; 284 | } 285 | 286 | public Double getSuodeShui() { 287 | return suodeShui; 288 | } 289 | 290 | public void setSuodeShui(Double suodeShui) { 291 | this.suodeShui = suodeShui; 292 | } 293 | 294 | public Double getMainBizIncome() { 295 | return mainBizIncome; 296 | } 297 | 298 | public void setMainBizIncome(Double mainBizIncome) { 299 | this.mainBizIncome = mainBizIncome; 300 | } 301 | 302 | 303 | } -------------------------------------------------------------------------------- /src/main/java/com/diffwind/stats/StockQuarterViewWind.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.stats; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.Date; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | import com.diffwind.util.DateUtil; 11 | 12 | /** 13 | * @20180128 更新: 14 | * 财报历史记录按报表日排序,不再使用披露日字段。股本变更记录按股本变动日期排序。 15 | * 16 | * @author billberg 17 | * 18 | */ 19 | public class StockQuarterViewWind { 20 | 21 | public final String symbol; 22 | //(倒序)时间序列 23 | //财报历史记录(季度),根据披露日排序,假设披露日排序不会打乱报表日排序,如造成报表日乱序,应抛出异常(不再使用披露日) 24 | //@20180128 财报历史记录(季度),根据财报日排序 25 | public final List quarterFinanceHist = new ArrayList(); 26 | //财报历史记录(年报) 27 | public final List yearFinanceHist = new ArrayList(); 28 | //股本变更历史记录(如果财报日有股本变更,则同时包含财报日) 29 | public final List sharesChgHist = new ArrayList(); 30 | 31 | //覆盖股本变更和财报历史记录,根据财报日和股本变动日排序(倒序) 32 | //TODO: 股本变更日与财报日重叠的情况,合并为财报日,案例: sz300255 33 | public final List financeChgHist = new ArrayList(); 34 | //日期索引 35 | public final Map lookupDate = new HashMap(); 36 | 37 | public StockQuarterViewWind(String symbol) { 38 | this.symbol = symbol; 39 | } 40 | 41 | public StockQuarterView at(Date d) { 42 | return lookupDate.get(d); 43 | } 44 | 45 | 46 | public void add_deprecated(StockQuarterView quarterView) { 47 | if (financeChgHist.size() > 0 && 48 | (quarterView.getPiluDate().compareTo(financeChgHist.get(financeChgHist.size()-1).getPiluDate()) > 0 49 | /*|| quarterView.getReportDate().compareTo(financeChgHist.get(financeChgHist.size()-1).getReportDate()) >= 0*/)) 50 | throw new RuntimeException(String.format("股本变更或财务历史数据时间乱序: %s > %s or %s >= %s", 51 | DateUtil.yyyyMMdd10.get().format(quarterView.getPiluDate()), DateUtil.yyyyMMdd10.get().format(financeChgHist.get(financeChgHist.size()-1).getPiluDate()), 52 | DateUtil.yyyyMMdd10.get().format(quarterView.getReportDate()), DateUtil.yyyyMMdd10.get().format(financeChgHist.get(financeChgHist.size()-1).getReportDate()) ) ); 53 | 54 | financeChgHist.add(quarterView); 55 | if ('F' == quarterView.getType()) { 56 | quarterFinanceHist.add(quarterView); 57 | if (quarterView.getReportQuarter() == 4) { 58 | yearFinanceHist.add(quarterView); 59 | } 60 | } else if ('G' == quarterView.getType()) { 61 | sharesChgHist.add(quarterView); 62 | } 63 | 64 | lookupDate.put(quarterView.getReportDate(), quarterView); 65 | } 66 | 67 | 68 | public void add(StockQuarterView quarterView) { 69 | 70 | financeChgHist.add(quarterView); 71 | 72 | if ('F' == quarterView.getType() || 'X' == quarterView.getType()) { 73 | quarterFinanceHist.add(quarterView); 74 | if (quarterView.getReportQuarter() == 4) { 75 | yearFinanceHist.add(quarterView); 76 | } 77 | } else if ('G' == quarterView.getType() || 'X' == quarterView.getType()) { 78 | sharesChgHist.add(quarterView); 79 | } 80 | 81 | lookupDate.put(quarterView.getReportDate(), quarterView); 82 | } 83 | 84 | public int size() { 85 | return financeChgHist.size(); 86 | } 87 | 88 | //TODO: 提供该方法不好,待完善 89 | public StockQuarterView get(int i) { 90 | return financeChgHist.get(i); 91 | } 92 | 93 | public void addAll(List quarterViewHist) { 94 | for (StockQuarterView qv : quarterViewHist) { 95 | add(qv); 96 | } 97 | } 98 | 99 | 100 | //TODO 101 | public String toString() { 102 | StringBuilder sb = new StringBuilder(); 103 | sb.append(String.format("-------- %s --------\n", symbol) ); 104 | 105 | String[] reportDate = quarterFinanceHist.stream().map(obj -> DateUtil.yyyyMMdd10.get().format(obj.getPiluDate()) +"@"+ DateUtil.yyyyMMdd10.get().format(obj.getReportDate())).toArray(String[]::new); 106 | sb.append("财报历史记录: ").append(Arrays.toString(reportDate)).append("\n"); 107 | reportDate = sharesChgHist.stream().map(obj -> DateUtil.yyyyMMdd10.get().format(obj.getReportDate())).toArray(String[]::new); 108 | sb.append("股本变更历史记录: ").append(Arrays.toString(reportDate)).append("\n"); 109 | reportDate = financeChgHist.stream().map(obj -> DateUtil.yyyyMMdd10.get().format(obj.getReportDate()) + obj.getType()).toArray(String[]::new); 110 | sb.append("股本变更和财报历史记录: ").append(Arrays.toString(reportDate)).append("\n"); 111 | 112 | sb.append(String.format("-------- %s --------\n", symbol) ); 113 | 114 | return sb.toString(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/stats/filters/FilterRules.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.stats.filters; 2 | 3 | /** 4 | * 规则库(规则的变更要保留历史版本): 5 | //高收益规则1:RANGE(v_netprofit,5) EACHGT 5.0e8 and RANGE(v_roe,5) EACHGT 10 6 | 7 | 行业规则示例:hangye == '电力行业' and RANGE(v_netprofit,5) EACHGT 5.0e8 and RANGE(v_roe,5) EACHGT 8 8 | 9 | * 主要盈利指标: netprofit, roe, roa 10 | * 主要成长指标: 净资产增长率, 净利润增长率 11 | * 主要风险指标: pe, pb 12 | * 主要规模指标: 净资产, 总资产 13 | * 14 | * 行业规则的确定,需要先对行业内股票做分类,以确定规则指标和指标阈值 15 | * @author billberg 16 | * 17 | */ 18 | public class FilterRules { 19 | 20 | //盈利指标矩阵:netprofit(10/5/2) x roe (20/15/10) 21 | //规则执行顺序为按照九宫格宽度优先执行? 22 | public static String YINGLI_11 = "(RANGE(v_netprofit,5) EACHGTE 10.0e8) and (RANGE(v_roe,5) EACHGTE 20)"; 23 | public static String YINGLI_12 = "(RANGE(v_netprofit,5) EACHGTE 5.0e8 and RANGE(v_netprofit,5) EACHLT 10.0e8) and (RANGE(v_roe,5) EACHGTE 20)"; 24 | public static String YINGLI_13 = "(RANGE(v_netprofit,5) EACHGT 2.0e8 and RANGE(v_netprofit,5) EACHLT 5.0e8) and (RANGE(v_roe,5) EACHGTE 20)"; 25 | public static String YINGLI_21 = "(RANGE(v_netprofit,5) EACHGTE 10.0e8) and (RANGE(v_roe,5) EACHGTE 15 and RANGE(v_roe,5) EACHLT 20)"; 26 | public static String YINGLI_22 = "(RANGE(v_netprofit,5) EACHGTE 5.0e8 and RANGE(v_netprofit,5) EACHLT 10.0e8) and (RANGE(v_roe,5) EACHGTE 15 and RANGE(v_roe,5) EACHLT 20)"; 27 | public static String YINGLI_23 = "(RANGE(v_netprofit,5) EACHGT 2.0e8 and RANGE(v_netprofit,5) EACHLT 5.0e8) and (RANGE(v_roe,5) EACHGTE 15 and RANGE(v_roe,5) EACHLT 20)"; 28 | public static String YINGLI_31 = "(RANGE(v_netprofit,5) EACHGTE 10.0e8) and (RANGE(v_roe,5) EACHGT 10 and RANGE(v_roe,5) EACHLT 15)"; 29 | public static String YINGLI_32 = "(RANGE(v_netprofit,5) EACHGTE 5.0e8 and RANGE(v_netprofit,5) EACHLT 10.0e8) and (RANGE(v_roe,5) EACHGT 10 and RANGE(v_roe,5) EACHLT 15)"; 30 | public static String YINGLI_33 = "(RANGE(v_netprofit,5) EACHGT 2.0e8 and RANGE(v_netprofit,5) EACHLT 5.0e8) and (RANGE(v_roe,5) EACHGT 10 and RANGE(v_roe,5) EACHLT 15)"; 31 | 32 | //规则横向表达,按标量方式?不如垂直方式的向量直观 33 | //foreach(list5Y.stk)(stk.netprofit >= 10.0e8 and stk.roe >= 20) 34 | //行业规则示例:hangye == '电力行业' and RANGE(v_netprofit,5) EACHGT 5.0e8 and RANGE(v_roe,5) EACHGT 8 35 | 36 | //实际规则: (netprofit > 1.0e9) and (pe > 0 and pe < 11) and (roe > 15 or pb < 1) 37 | //筛选时放松pe条件观察优质股的情况 38 | //TODO: 规则改成最近2年的指标约束,以过滤垃圾企业 39 | //指标阈值的处理,先检查样本分布,比如确定netprofit的阈值,先通过(pe > 0 and pe < 15) and (roe > 15 or pb < 1)选择样本集合 40 | public static String LONGWINDCASES_01 = "(netprofit > 5.0e8) and (pe > 0 and pe < 11) and (roe > 15 or pb < 1)"; 41 | 42 | @Deprecated 43 | public static String MINGXING_5Y = "(RANGE(v_netprofit,5) EACHGT 2.0e8) and (RANGE(v_roe,5) EACHGT 15)"; 44 | @Deprecated 45 | public static String MINGXING_20Q = "(RANGE(v_netprofit4Q,20) EACHGT 2.0e8) and (RANGE(v_roe4Q,20) EACHGT 15)"; 46 | @Deprecated 47 | public static String MINGXING_10Y = "(RANGE(v_netprofit,10) EACHGT 2.0e8) and (RANGE(v_roe,10) EACHGT 10)"; 48 | 49 | //同时约束每年和滑动均值 50 | @Deprecated 51 | public static String MINGXING_$Y_MA5 = "(RANGE(v_netprofit,{0}) EACHGT 2.0e8) and (RANGE(MA(v_roe,5),{0}) EACHGT 15)"; 52 | 53 | @Deprecated 54 | public static String VALUE_$Y_MA5old = "WHICH[" 55 | //明星 56 | + "(RANGE(v_netprofit,{0}) EACHGT 2.0e8) and (RANGE(MA(v_roe,5),{0}) EACHGT 15)," 57 | //高净利润 58 | + "(RANGE(v_netprofit,{0}) EACHGT 2.0e8) and (RANGE(v_roe,{0}) EACHGT 10)," 59 | //高ROE 60 | + "(RANGE(v_netprofit,{0}) EACHGT 1.0e8) and (RANGE(MA(v_roe,5),{0}) EACHGT 15)," 61 | + "1 >= 0]"; 62 | 63 | public static String YINGLI_$Y = "WHICH[" 64 | //明星 65 | + "(RANGE(v_netprofit,5) EACHGT 2.0e8) and (RANGE(MA(v_roe,3),{0}) EACHGT 15)," 66 | //高净利润 67 | + "(RANGE(v_netprofit,5) EACHGT 5.0e8) and (RANGE(v_roe,{0}) EACHGT 10)," 68 | //高ROE 69 | + "(RANGE(v_netprofit,5) EACHGT 1.0e8) and (RANGE(MA(v_roe,3),{0}) EACHGT 15)," 70 | //高成长 71 | + "(RANGE(v_totalAssets,5) EACHGT 50.0e8) and (RANGE(v_totalNetAssets,5) EACHGT 20.0e8) " 72 | + "and (RANGE(v_totalAssetsGrowthRate,5) EACHGT 15) and (RANGE(v_totalNetAssetsGrowthRate,5) EACHGT 15)," 73 | + "1 >= 0]"; 74 | 75 | 76 | //两步筛选 77 | //1-所得税 2-盈利能力 78 | //所得税费用 > 1e8 and 实际所得税率 > 0.1 79 | //TODO: EBIT, EBITDA 80 | public static String YINGLI1_SUODESHUI = "(RANGE(v_suodeshui,3) EACHGT 1.0e8) and (RANGE(v_suodeshuiRate,3) EACHGT 0.1)" 81 | ; 82 | 83 | //盈利与成长(成长性非常重要-Alpha) 84 | //成长性只看近3年,有历史数据缺失问题 85 | //无法处理周期股 86 | public static String YINGLI2_CLASS_$Y = "WHICH[" 87 | //1-明星(盈利+成长) 88 | + "(RANGE(v_netprofit,5) EACHGT 2.0e8) and (RANGE(v_roe,5) EACHGT 15) " 89 | + "and ((RANGE(MA(v_totalAssetsGrowthRate,2),5) EACHGT 15) or (RANGE(MA(v_mainBizIncomeGrowthRate,2),5) EACHGT 15))," 90 | //2-高成长 91 | //+ "(RANGE(v_totalAssets,5) EACHGT 50.0e8) and (RANGE(v_totalNetAssets,5) EACHGT 10.0e8) " 92 | //+ "and (RANGE(v_totalAssetsGrowthRate,5) EACHGT 10) and (RANGE(v_totalNetAssetsGrowthRate,5) EACHGT 10)," 93 | //+ "(RANGE(v_totalAssets,5) EACHGT 50.0e8) and (RANGE(v_totalNetAssets,5) EACHGT 10.0e8) " 94 | + "(RANGE(v_netprofit,5) EACHGT 1.0e8) and (RANGE(v_roe,5) EACHGT 10) " 95 | + "and ((RANGE(MA(v_totalAssetsGrowthRate,2),5) EACHGT 15) or (RANGE(MA(v_mainBizIncomeGrowthRate,2),5) EACHGT 15))," 96 | //3-高ROE 97 | + "(RANGE(v_netprofit,5) EACHGT 1.0e8) and (RANGE(MA(v_roe,2),5) EACHGT 15)," 98 | //4-高净利润 99 | + "(RANGE(v_netprofit,5) EACHGT 5.0e8) and (RANGE(v_roe,5) EACHGT 10)," 100 | //5-良好 101 | + "(RANGE(v_netprofit,5) EACHGT 1.0e8) and (RANGE(v_roe,5) EACHGT 10)," 102 | //6-近3年关注 103 | + "(RANGE(v_netprofit,3) EACHGT 1.0e8) and (RANGE(v_roe,3) EACHGT 15) " 104 | //+ "and (RANGE(MA(v_totalAssetsGrowthRate,2),3) EACHGT 20)," 105 | + "and ((RANGE(MA(v_totalAssetsGrowthRate,2),3) EACHGT 20) or (RANGE(MA(v_mainBizIncomeGrowthRate,2),3) EACHGT 20))," 106 | 107 | + "1 >= 0]"; 108 | 109 | 110 | //根据成长性筛选 111 | //重点考虑总资产增长率、营业收入增长率与营业税? 112 | public static String CHENGZHANG1 = ""; 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/stats/stats.sql: -------------------------------------------------------------------------------- 1 | -- 根据净利润规模筛选,重点关注行业龙头 2 | select f.*,h.name,h.hyname 3 | from xueqiu_stock_finance f, sina_zjhhangye_stock h 4 | where f.symbol = h.symbol 5 | and f.reportdate = '2016-12-31' 6 | and f.netprofit > 2*1e8 -- 根据行业调整 7 | and f.weightedroe > 7 -- 根据行业调整 8 | order by h.hyname, f.netprofit desc; 9 | 10 | 11 | -- 连续3年盈利指标筛选,重点关注行业龙头 12 | -- 再结合风险指标PE/PB 13 | with q1 as (select f.* 14 | from xueqiu_stock_finance f 15 | where f.reportdate = '2016-12-31' 16 | and f.netprofit > 10*1e8 -- 根据行业调整 17 | and f.weightedroe > 10 -- 根据行业调整 18 | ), q2 as (select f.* 19 | from xueqiu_stock_finance f 20 | where f.reportdate = '2015-12-31' 21 | and f.netprofit > 10*1e8 -- 根据行业调整 22 | and f.weightedroe > 10 -- 根据行业调整 23 | ), q3 as (select f.* 24 | from xueqiu_stock_finance f 25 | where f.reportdate = '2014-12-31' 26 | and f.netprofit > 10*1e8 -- 根据行业调整 27 | and f.weightedroe > 10 -- 根据行业调整 28 | ), q4 as ( 29 | select q1.* 30 | from q1, q2, q3 31 | where q1.symbol = q2.symbol 32 | and q1.symbol = q3.symbol 33 | ) 34 | select q4.reportdate "报表日期",q4.symbol "代码",h.name "名称",h.hyname "行业/板块", 35 | q4.netprofit "净利润",q4.weightedroe "净资产收益率(加权)",100*q4.netprofit/q4.totalassets "总资产收益率", 36 | q4.mainbusiincome "主营业务收入", q4.mainbusiprofit "主营业务利润", 37 | q4.netassgrowrate "净资产增长率", q4.mainbusincgrowrate "主营业务收入增长率", 38 | q4.netincgrowrate "净利润增长率", q4.totassgrowrate "总资产增长率", 39 | q4.totalassets "资产总额", q4.totalliab "负债总额", q4.totsharequi "股东权益合计", q4.cashequfinbal "期末现金及现金等价物余额" 40 | from q4, sina_zjhhangye_stock h 41 | where q4.symbol = h.symbol 42 | order by h.hyname, q4.netprofit desc 43 | ; 44 | 45 | 46 | -- 连续5年盈利指标筛选,重点关注行业龙头 47 | -- 再结合风险指标PE/PB 48 | @Deprecated 49 | with q1 as (select f.* 50 | from xueqiu_stock_finance f 51 | where f.reportdate = '2016-12-31' 52 | and f.netprofit > 10*1e8 -- 根据行业调整 53 | and f.weightedroe > 10 -- 根据行业调整 54 | ), q2 as (select f.* 55 | from xueqiu_stock_finance f 56 | where f.reportdate = '2015-12-31' 57 | and f.netprofit > 10*1e8 -- 根据行业调整 58 | and f.weightedroe > 10 -- 根据行业调整 59 | ), q3 as (select f.* 60 | from xueqiu_stock_finance f 61 | where f.reportdate = '2014-12-31' 62 | and f.netprofit > 10*1e8 -- 根据行业调整 63 | and f.weightedroe > 10 -- 根据行业调整 64 | ), q4 as (select f.* 65 | from xueqiu_stock_finance f 66 | where f.reportdate = '2013-12-31' 67 | and f.netprofit > 10*1e8 -- 根据行业调整 68 | and f.weightedroe > 10 -- 根据行业调整 69 | ), q5 as (select f.* 70 | from xueqiu_stock_finance f 71 | where f.reportdate = '2012-12-31' 72 | and f.netprofit > 10*1e8 -- 根据行业调整 73 | and f.weightedroe > 10 -- 根据行业调整 74 | ), qx as ( 75 | select q1.* 76 | from q1, q2, q3, q4, q5 77 | where q1.symbol = q2.symbol 78 | and q1.symbol = q3.symbol 79 | and q1.symbol = q4.symbol 80 | and q1.symbol = q5.symbol 81 | ) 82 | select qx.reportdate "报表日期",qx.symbol "代码",h.name "名称",h.hyname "行业/板块", 83 | qx.netprofit "净利润",qx.weightedroe "净资产收益率(加权)",100*qx.netprofit/qx.totalassets "总资产收益率", 84 | qx.mainbusiincome "主营业务收入", qx.mainbusiprofit "主营业务利润", 85 | qx.netassgrowrate "净资产增长率", qx.mainbusincgrowrate "主营业务收入增长率", 86 | qx.netincgrowrate "净利润增长率", qx.totassgrowrate "总资产增长率", 87 | qx.totalassets "资产总额", qx.totalliab "负债总额", qx.totsharequi "股东权益合计", qx.cashequfinbal "期末现金及现金等价物余额" 88 | from qx, sina_zjhhangye_stock h 89 | where qx.symbol = h.symbol 90 | order by h.hyname, qx.netprofit desc 91 | ; 92 | 93 | 94 | -- 连续5年盈利指标筛选,重点关注行业龙头 95 | -- 再结合风险指标PE/PB 96 | with qx as (select f1.* 97 | from xueqiu_stock_finance f1,xueqiu_stock_finance f2,xueqiu_stock_finance f3,xueqiu_stock_finance f4,xueqiu_stock_finance f5 98 | where f1.reportdate = make_date(extract(year from now())::int-1,12,31) 99 | and f1.netprofit > 10*1e8 -- 根据行业调整 100 | and f1.weightedroe > 10 -- 根据行业调整 101 | and f2.reportdate = make_date(extract(year from now())::int-2,12,31) 102 | and f2.netprofit > 10*1e8 -- 根据行业调整 103 | and f2.weightedroe > 10 -- 根据行业调整 104 | and f3.reportdate = make_date(extract(year from now())::int-3,12,31) 105 | and f3.netprofit > 10*1e8 -- 根据行业调整 106 | and f3.weightedroe > 10 -- 根据行业调整 107 | and f4.reportdate = make_date(extract(year from now())::int-4,12,31) 108 | and f4.netprofit > 10*1e8 -- 根据行业调整 109 | and f4.weightedroe > 10 -- 根据行业调整 110 | and f5.reportdate = make_date(extract(year from now())::int-5,12,31) 111 | and f5.netprofit > 10*1e8 -- 根据行业调整 112 | and f5.weightedroe > 10 -- 根据行业调整 113 | and f1.symbol = f2.symbol 114 | and f1.symbol = f3.symbol 115 | and f1.symbol = f4.symbol 116 | and f1.symbol = f5.symbol 117 | ) 118 | select qx.reportdate "报表日期",qx.symbol "代码",h.name "名称",h.hycode "行业代码",h.hyname "行业/板块", 119 | qx.netprofit "净利润",qx.weightedroe "净资产收益率(加权)",100*qx.netprofit/qx.totalassets "总资产收益率", 120 | qx.mainbusiincome "主营业务收入", qx.mainbusiprofit "主营业务利润", 121 | qx.netassgrowrate "净资产增长率", qx.mainbusincgrowrate "主营业务收入增长率", 122 | qx.netincgrowrate "净利润增长率", qx.totassgrowrate "总资产增长率", 123 | qx.totalassets "资产总额", qx.totalliab "负债总额", qx.totsharequi "股东权益合计", qx.cashequfinbal "期末现金及现金等价物余额" 124 | from qx, sina_zjhhangye_stock h 125 | where qx.symbol = h.symbol 126 | -- and h.hycode like 'hangye%' -- 只输出行业不输出概念板块 127 | order by h.hycode desc, qx.netprofit desc 128 | ; 129 | 130 | -- 连续5年盈利指标筛选,重点关注行业龙头 131 | -- 再结合风险指标PE/PB 132 | -- 高roe筛选 133 | with qx as (select f1.* 134 | from xueqiu_stock_finance f1,xueqiu_stock_finance f2,xueqiu_stock_finance f3,xueqiu_stock_finance f4,xueqiu_stock_finance f5 135 | where f1.reportdate = make_date(extract(year from now())::int-1,12,31) 136 | and f1.netprofit > 2*1e8 -- 根据行业调整 137 | and f1.weightedroe > 20 -- 根据行业调整 138 | and f2.reportdate = make_date(extract(year from now())::int-2,12,31) 139 | and f2.netprofit > 2*1e8 -- 根据行业调整 140 | and f2.weightedroe > 20 -- 根据行业调整 141 | and f3.reportdate = make_date(extract(year from now())::int-3,12,31) 142 | and f3.netprofit > 2*1e8 -- 根据行业调整 143 | and f3.weightedroe > 20 -- 根据行业调整 144 | and f4.reportdate = make_date(extract(year from now())::int-4,12,31) 145 | and f4.netprofit > 2*1e8 -- 根据行业调整 146 | and f4.weightedroe > 20 -- 根据行业调整 147 | and f5.reportdate = make_date(extract(year from now())::int-5,12,31) 148 | and f5.netprofit > 2*1e8 -- 根据行业调整 149 | and f5.weightedroe > 20 -- 根据行业调整 150 | and f1.symbol = f2.symbol 151 | and f1.symbol = f3.symbol 152 | and f1.symbol = f4.symbol 153 | and f1.symbol = f5.symbol 154 | ) 155 | select qx.reportdate "报表日期",qx.symbol "代码",h.name "名称",h.hycode "行业代码",h.hyname "行业/板块", 156 | qx.netprofit "净利润",qx.weightedroe "净资产收益率(加权)",100*qx.netprofit/qx.totalassets "总资产收益率", 157 | qx.mainbusiincome "主营业务收入", qx.mainbusiprofit "主营业务利润", 158 | qx.netassgrowrate "净资产增长率", qx.mainbusincgrowrate "主营业务收入增长率", 159 | qx.netincgrowrate "净利润增长率", qx.totassgrowrate "总资产增长率", 160 | qx.totalassets "资产总额", qx.totalliab "负债总额", qx.totsharequi "股东权益合计", qx.cashequfinbal "期末现金及现金等价物余额" 161 | from qx, sina_zjhhangye_stock h 162 | where qx.symbol = h.symbol 163 | -- and h.hycode like 'hangye%' -- 只输出行业不输出概念板块 164 | order by h.hycode desc, qx.netprofit desc 165 | ; 166 | 167 | 168 | -- 根据盈利指标做聚类分析 169 | select f1.* 170 | from xueqiu_stock_finance f1 171 | where f1.reportdate = make_date(extract(year from now())::int-1,12,31) 172 | and f1.netprofit > 0 173 | and f1.netprofit < 100*1e8 174 | and f1.weightedroe > 0 175 | ; -------------------------------------------------------------------------------- /src/main/java/com/diffwind/util/Algorithm.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.util; 2 | 3 | public class Algorithm { 4 | 5 | public static int[] bubbleSortDescending(double[] arr){ 6 | //排序后位置->元素索引 7 | int[] order = new int[arr.length]; 8 | //元素索引->位置 9 | 10 | for (int i = 0; i < arr.length;i++) 11 | order[i] = i; 12 | 13 | int temp; 14 | for(int i=0; i < arr.length-1; i++){ 15 | 16 | for(int j=1; j < arr.length-i; j++){//最小值交换到最后 17 | /*if(arr[j-1] < arr[j]){ 18 | temp=arr[j-1]; 19 | arr[j-1] = arr[j]; 20 | arr[j] = temp;*/ 21 | 22 | if(arr[order[j-1]] < arr[order[j]]){ 23 | 24 | //int t; 25 | temp = order[j-1]; 26 | order[j-1] = order[j]; 27 | order[j] = temp; 28 | } 29 | } 30 | //check that last index has highest value in first loop, 31 | // second last index has second last highest value and so on 32 | //System.out.println("Array after "+(i+1)+"th iteration:"+Arrays.toString(arr)); 33 | //System.out.println("Order after "+(i+1)+"th iteration:"+Arrays.toString(order)); 34 | } 35 | 36 | return order; 37 | } 38 | 39 | public static int[] bubbleSortAscending(double[] arr){ 40 | //排序后位置->元素索引 41 | int[] order = new int[arr.length]; 42 | //元素索引->位置 43 | 44 | for (int i = 0; i < arr.length;i++) 45 | order[i] = i; 46 | 47 | int temp; 48 | for(int i=0; i < arr.length-1; i++){ 49 | 50 | for(int j=1; j < arr.length-i; j++){//最大值交换到最后 51 | /*if(arr[j-1] < arr[j]){ 52 | temp=arr[j-1]; 53 | arr[j-1] = arr[j]; 54 | arr[j] = temp;*/ 55 | 56 | if(arr[order[j-1]] > arr[order[j]]){ 57 | 58 | //int t; 59 | temp = order[j-1]; 60 | order[j-1] = order[j]; 61 | order[j] = temp; 62 | } 63 | } 64 | //check that last index has highest value in first loop, 65 | // second last index has second last highest value and so on 66 | //System.out.println("Array after "+(i+1)+"th iteration:"+Arrays.toString(arr)); 67 | //System.out.println("Order after "+(i+1)+"th iteration:"+Arrays.toString(order)); 68 | } 69 | 70 | return order; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/util/DateUtil.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.util; 2 | 3 | import java.text.DateFormat; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Calendar; 6 | import java.util.Date; 7 | 8 | public class DateUtil { 9 | 10 | // SimpleDateFormat是线程不安全的,采用这种方式避免 11 | public static ThreadLocal yyyyMMdd = new ThreadLocal() { 12 | @Override 13 | protected synchronized DateFormat initialValue() { 14 | return new SimpleDateFormat("yyyyMMdd"); 15 | } 16 | }; 17 | 18 | public static ThreadLocal yyyyMMddLine = new ThreadLocal() { 19 | @Override 20 | protected synchronized DateFormat initialValue() { 21 | return new SimpleDateFormat("yyyy/MM/dd"); 22 | } 23 | }; 24 | 25 | public static ThreadLocal YYMMDD = new ThreadLocal() { 26 | @Override 27 | protected synchronized DateFormat initialValue() { 28 | return new SimpleDateFormat("yyMMdd"); 29 | } 30 | }; 31 | 32 | public static ThreadLocal HHmmss = new ThreadLocal() { 33 | @Override 34 | protected synchronized DateFormat initialValue() { 35 | return new SimpleDateFormat("HHmmss"); 36 | } 37 | }; 38 | 39 | public static ThreadLocal yyyyMMdd10 = new ThreadLocal() { 40 | @Override 41 | protected synchronized DateFormat initialValue() { 42 | return new SimpleDateFormat("yyyy-MM-dd"); 43 | } 44 | }; 45 | 46 | public static ThreadLocal formatter14 = new ThreadLocal() { 47 | @Override 48 | protected synchronized DateFormat initialValue() { 49 | return new SimpleDateFormat("yyyyMMddHHmmss"); 50 | } 51 | }; 52 | 53 | public static ThreadLocal formatter18 = new ThreadLocal() { 54 | @Override 55 | protected synchronized DateFormat initialValue() { 56 | return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 57 | } 58 | }; 59 | 60 | public static ThreadLocal yyyyMM = new ThreadLocal() { 61 | @Override 62 | protected synchronized DateFormat initialValue() { 63 | return new SimpleDateFormat("yyyyMM"); 64 | } 65 | }; 66 | 67 | public static ThreadLocal yyyy = new ThreadLocal() { 68 | @Override 69 | protected synchronized DateFormat initialValue() { 70 | return new SimpleDateFormat("yyyy"); 71 | } 72 | }; 73 | 74 | public static ThreadLocal MMdd = new ThreadLocal() { 75 | @Override 76 | protected synchronized DateFormat initialValue() { 77 | return new SimpleDateFormat("MMdd"); 78 | } 79 | }; 80 | 81 | public static Date getLastMonth() { 82 | Calendar cal = Calendar.getInstance(); 83 | cal.add(Calendar.MONTH, -1); 84 | cal.set(Calendar.DAY_OF_MONTH, 1); 85 | return cal.getTime(); 86 | } 87 | 88 | public static int getDaysBetween(Date startDate, Date endDate) { 89 | Calendar cal = Calendar.getInstance(); 90 | cal.setTime(startDate); 91 | 92 | Calendar cal2 = Calendar.getInstance(); 93 | cal2.setTime(endDate); 94 | 95 | return (int)((cal2.getTimeInMillis() - cal.getTimeInMillis())/(1000*3600*24)); 96 | } 97 | 98 | public static int getHoursBetween(Date startDate, Date endDate) { 99 | Calendar cal = Calendar.getInstance(); 100 | cal.setTime(startDate); 101 | 102 | Calendar cal2 = Calendar.getInstance(); 103 | cal2.setTime(endDate); 104 | 105 | return (int)((cal2.getTimeInMillis() - cal.getTimeInMillis())/(1000*3600)); 106 | } 107 | 108 | //根据日期找到上一个最近的财报日 109 | public static Date getLastFinanceReportDate(Date date) { 110 | Calendar cal = Calendar.getInstance(); 111 | 112 | cal.setTime(date); 113 | int year = cal.get(Calendar.YEAR); 114 | int month = cal.get(Calendar.MONTH) + 1; 115 | 116 | int financeReportYear, financeReportMonth; 117 | if (month <= 3) { 118 | financeReportYear = year - 1; 119 | financeReportMonth = 12; 120 | } else { 121 | financeReportYear = year; 122 | financeReportMonth = 3*((month-1)/3); 123 | } 124 | 125 | cal.set(financeReportYear, financeReportMonth - 1, 1); 126 | cal.set(Calendar.DATE, cal.getActualMaximum(Calendar.DATE)); 127 | 128 | return cal.getTime(); 129 | } 130 | 131 | 132 | public static Date getLastDayOfMonth(Date date) { 133 | Calendar cal = Calendar.getInstance(); 134 | 135 | cal.setTime(date); 136 | //int year = cal.get(Calendar.YEAR); 137 | //int month = cal.get(Calendar.MONTH); 138 | //cal.set(year, month, 1); 139 | cal.set(Calendar.DATE, cal.getActualMaximum(Calendar.DATE)); 140 | 141 | return cal.getTime(); 142 | } 143 | 144 | public static Date getLastDayOfMonth(int year, int month) { 145 | Calendar cal = Calendar.getInstance(); 146 | cal.set(year, month-1, 1); 147 | cal.set(Calendar.DATE, cal.getActualMaximum(Calendar.DATE)); 148 | 149 | return cal.getTime(); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/util/DoubleCheck.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.util; 2 | 3 | public class DoubleCheck { 4 | public static boolean checkHasNa(Double... args) { 5 | for (Double d : args) { 6 | if (d == null || d.isNaN()) 7 | return true; 8 | } 9 | 10 | return false; 11 | } 12 | 13 | public static boolean checkPositive(Double... args) { 14 | for (Double d : args) { 15 | if (d == null || d < 0d) 16 | return false; 17 | } 18 | 19 | return true; 20 | } 21 | 22 | 23 | public static Double ifNull2NaN(Double d) { 24 | if (d == null) 25 | return Double.NaN; 26 | 27 | return d; 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/util/Functions.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.util; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.Iterator; 5 | 6 | public class Functions { 7 | 8 | //简单收益率 9 | //simR+1 = c1/c2 10 | public static double simR(double c1, double c2) { 11 | return (c1-c2)/c2; 12 | } 13 | 14 | //对数收益率 15 | //logR = log(simR+1) = log(C2) - log(C1) 16 | //simR = exp(logR) - 1 17 | public static double logR(double c1, double c2) { 18 | return Math.log(c1/c2); 19 | } 20 | 21 | public static double simR2logR(double simR) { 22 | return Math.log(simR+1); 23 | } 24 | 25 | public static double logR2simR(double logR) { 26 | return Math.pow(Math.E, logR) - 1; 27 | } 28 | 29 | //根据长窗口收益计算微分窗口收益 30 | public static double calcDiffWindReturn(int longW, double longWChg, int shortW) { 31 | //先计算日对数收益,再计算shortW窗口收益 32 | double day_r = Functions.simR2logR(longWChg)/longW; 33 | double shortW_r = shortW*day_r; 34 | double shortW_R = Functions.logR2simR(shortW_r); 35 | return 100*shortW_R; 36 | } 37 | 38 | /** 39 | * 时间序列(倒序)对数收益率 40 | * 更新: 添加最后一个收益率为0,使收益率序列长度与原序列长度一致 41 | * TODO: 回滚上次的更新 42 | * @param ts 43 | * @return 44 | */ 45 | public static double[] logR(double[] ts, int order) { 46 | double[] logr = new double[ts.length]; 47 | if (order == -1) { 48 | logr[ts.length-1] = 0; 49 | for (int i = 0; i < ts.length-1; i++) 50 | logr[i] = Math.log(ts[i]/ts[i+1]); 51 | } else { 52 | throw new RuntimeException("未实现"); 53 | } 54 | 55 | return logr; 56 | } 57 | 58 | 59 | /** 60 | * 时间序列(倒序)简单收益率 61 | * 更新: 添加最后一个收益率为0,使收益率序列长度与原序列长度一致 62 | * TODO: 回滚上次的更新 63 | * @param ts 64 | * @return 65 | */ 66 | public static double[] simR(double[] ts, int order) { 67 | double[] simr = new double[ts.length]; 68 | if (order == -1) { 69 | simr[ts.length-1] = 0; 70 | for (int i = 0; i < ts.length-1; i++) 71 | simr[i] = ts[i]/ts[i+1] - 1; 72 | } else { 73 | throw new RuntimeException("未实现"); 74 | } 75 | 76 | return simr; 77 | } 78 | 79 | 80 | public static Double[] simR(Double[] ts, int order) { 81 | Double[] simr = new Double[ts.length]; 82 | if (order == -1) { 83 | simr[ts.length-1] = 0d; 84 | for (int i = 0; i < ts.length-1; i++) { 85 | if (ts[i] == null || ts[i+1] == null) 86 | break; 87 | 88 | simr[i] = ts[i]/ts[i+1] - 1; 89 | } 90 | } else { 91 | throw new RuntimeException("未实现"); 92 | } 93 | 94 | return simr; 95 | } 96 | 97 | public static double[] multiply(double[] ts, double d) { 98 | double[] result = new double[ts.length]; 99 | for (int i = 0; i < ts.length; i++) 100 | result[i] = ts[i]*d; 101 | 102 | return result; 103 | } 104 | 105 | public static Double[] multiply(Double[] ts, double d) { 106 | Double[] result = new Double[ts.length]; 107 | for (int i = 0; i < ts.length; i++) { 108 | if (ts[i] == null) 109 | break; 110 | 111 | result[i] = ts[i]*d; 112 | } 113 | 114 | return result; 115 | } 116 | 117 | public static double[] cumsum(double[] ts, int order) { 118 | double[] result = new double[ts.length]; 119 | double cumsum = 0; 120 | if (order == -1) { 121 | for (int i = ts.length-1; i >= 0; i--) { 122 | cumsum = cumsum + ts[i]; 123 | result[i] = cumsum; 124 | } 125 | } else { 126 | throw new RuntimeException("未实现"); 127 | } 128 | 129 | return result; 130 | } 131 | 132 | //必须保证不丢失信息 133 | public static double[] cumsub(double[] ts, int order) { 134 | double[] result = new double[ts.length]; 135 | double cumsub = 0; 136 | if (order == 1) { 137 | for (int i = 0; i < ts.length; i++) { 138 | cumsub = cumsub - ts[i]; 139 | result[i] = cumsub; 140 | } 141 | } else { 142 | throw new RuntimeException("未实现"); 143 | } 144 | 145 | return result; 146 | } 147 | 148 | /** 149 | * 从0开始求累积和 150 | * @param ts 151 | * @param order 152 | * @return 比原序列长度加1 153 | */ 154 | public static double[] cumsum0(double[] ts, int order) { 155 | double[] result = new double[ts.length+1]; 156 | double cumsum = 0; 157 | if (order == -1) { 158 | result[ts.length] = 0; 159 | for (int i = ts.length-1; i >= 0; i--) { 160 | cumsum = cumsum + ts[i]; 161 | result[i] = cumsum; 162 | } 163 | } else { 164 | throw new RuntimeException("未实现"); 165 | } 166 | 167 | return result; 168 | } 169 | 170 | /** 171 | * 从0开始求累积差 172 | * @param ts 173 | * @param order 174 | * @return 175 | */ 176 | public static double[] cumsub0(double[] ts, int order) { 177 | double[] result = new double[ts.length+1]; 178 | double cumsub = 0; 179 | if (order == 1) { 180 | result[0] = 0; 181 | for (int i = 0; i < ts.length; i++) { 182 | cumsub = cumsub - ts[i]; 183 | result[i+1] = cumsub; 184 | } 185 | } else { 186 | throw new RuntimeException("未实现"); 187 | } 188 | 189 | return result; 190 | } 191 | 192 | 193 | /* 194 | public static double[] logR(double[] ts) { 195 | double[] r = new double[ts.length-1]; 196 | for (int i = 0; i < ts.length-1; i++) 197 | r[i] = Math.log(ts[i]/ts[i+1]); 198 | 199 | return r; 200 | } 201 | */ 202 | 203 | /** 204 | * 查找最大值所在序号 205 | * 206 | * @param arr 207 | * @param startIndex 数组开始下标,包含 208 | * @param endIndex 数组结束下标,不包含 209 | * @return 210 | */ 211 | public static int whichMax(double[] arr, int startIndex, int endIndex) { 212 | //assert (startIndex >= 0 && startIndex < endIndex && endIndex <= arr.length); 213 | if (!(startIndex >= 0 && startIndex < endIndex && endIndex <= arr.length)) { 214 | return -1; 215 | } 216 | 217 | int pos = startIndex; 218 | for (int i = startIndex+1; i < endIndex; i++) { 219 | if (arr[i] > arr[pos]) { 220 | pos = i; 221 | } 222 | } 223 | 224 | return pos; 225 | } 226 | 227 | /** 228 | * 查找最小值所在序号 229 | * 230 | * @param arr 231 | * @param startIndex 数组开始下标,包含 232 | * @param endIndex 数组结束下标,不包含 233 | * @return 234 | */ 235 | public static int whichMin(double[] arr, int startIndex, int endIndex) { 236 | //assert (startIndex >= 0 && startIndex < endIndex && endIndex <= arr.length); 237 | if (!(startIndex >= 0 && startIndex < endIndex && endIndex <= arr.length)) { 238 | return -1; 239 | } 240 | 241 | int pos = startIndex; 242 | for (int i = startIndex+1; i < endIndex; i++) { 243 | if (arr[i] < arr[pos]) { 244 | pos = i; 245 | } 246 | } 247 | 248 | return pos; 249 | } 250 | 251 | public static double min(double[] arr) { 252 | if (checkHasNa(arr)) { 253 | return Double.NaN; 254 | } 255 | 256 | double minValue = arr[0]; 257 | for (int i = 1; i < arr.length; i++) { 258 | if (arr[i] < minValue) { 259 | minValue = arr[i]; 260 | } 261 | } 262 | 263 | return minValue; 264 | } 265 | 266 | public static boolean checkHasNa(double[] arr) { 267 | for (int i = 0; i < arr.length; i++) { 268 | if (Double.isNaN(arr[i])) 269 | return true; 270 | } 271 | 272 | return false; 273 | } 274 | 275 | public static double round(double d) { 276 | if (Double.isNaN(d) || Double.isInfinite(d)) 277 | return d; 278 | 279 | return new BigDecimal(Double.toString(d)).setScale(2,java.math.BigDecimal.ROUND_HALF_UP).doubleValue(); 280 | } 281 | 282 | public static double[] round(double[] d) { 283 | double[] rd = new double[d.length]; 284 | for (int i = 0; i < d.length; i++) { 285 | rd[i] = round(d[i]); 286 | } 287 | 288 | return rd; 289 | } 290 | 291 | public static boolean in(int x, int[] arr) { 292 | for (int i = 0; i < arr.length; i++) { 293 | if (x == arr[i]) 294 | return true; 295 | } 296 | 297 | return false; 298 | } 299 | 300 | } 301 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/util/PGCopy.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.util; 2 | 3 | import java.beans.Statement; 4 | import java.io.File; 5 | import java.sql.Connection; 6 | import java.sql.DriverManager; 7 | import java.sql.PreparedStatement; 8 | 9 | import com.diffwind.dao.mapper.TruncateTableMapper; 10 | 11 | public class PGCopy { 12 | 13 | private static String OUTPUT_PATH = "xueqiu.day/"; 14 | 15 | public static void main(String args[]) { 16 | Connection c = null; 17 | PreparedStatement stmt = null; 18 | try { 19 | Class.forName("org.postgresql.Driver"); 20 | c = DriverManager.getConnection("jdbc:postgresql://localhost:5432/diffview", "zhangjz", ""); 21 | c.setAutoCommit(false); 22 | System.out.println("Opened database successfully"); 23 | 24 | /* 25 | String truncateTableSql = "truncate table xueqiu_stock_day"; 26 | 27 | stmt = c.prepareStatement(truncateTableSql); 28 | 29 | stmt.execute(); 30 | 31 | String copySql = "copy xueqiu_stock_day from '%s'" 32 | + " with (FORMAT csv, DELIMITER ',',header true,quote '\"',encoding 'UTF8')"; 33 | 34 | File dir = new File(OUTPUT_PATH); 35 | File[] dayFiles = dir.listFiles(); 36 | 37 | for (int i = 0; i < dayFiles.length; i++) { 38 | File stockDay = dayFiles[i]; 39 | 40 | String filePath = stockDay.getAbsolutePath(); 41 | 42 | stmt = c.prepareStatement(String.format(copySql, filePath)); 43 | 44 | stmt.execute(); 45 | 46 | System.out.println("Finished:" + (i + 1)); 47 | 48 | } 49 | 50 | 51 | String createIndexSql = "CREATE INDEX idx1_xueqiu_stock_day ON xueqiu_stock_day (symbol);"; 52 | stmt = c.prepareStatement(createIndexSql); 53 | stmt.execute(); 54 | */ 55 | String createIndexSql = "CREATE INDEX idx2_xueqiu_stock_day ON xueqiu_stock_day (date);"; 56 | stmt = c.prepareStatement(createIndexSql); 57 | stmt.execute(); 58 | 59 | 60 | stmt.close(); 61 | c.close(); 62 | } catch (Exception e) { 63 | System.err.println(e.getClass().getName() + ": " + e.getMessage()); 64 | System.exit(0); 65 | } 66 | System.out.println("Operation done successfully"); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/util/RiskProb.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.util; 2 | 3 | /** 4 | * 风险的度量方法,应更准确 5 | * @author billberg 6 | * 7 | */ 8 | public class RiskProb { 9 | 10 | // 11 | @Deprecated 12 | public static double[] evaRiskProb(double[] ts, double maxRiskProb) { 13 | int[] order = Algorithm.bubbleSortAscending(ts); 14 | int pos = 0; 15 | for (int i = 0; i < order.length; i++) 16 | if (order[i] == 0) { 17 | pos = i; 18 | break; 19 | } 20 | 21 | //当前风险概率水平 22 | double riskProb = (pos+1)/(double)order.length; 23 | //满足风险条件的参考值 24 | double riskMark = 0d; 25 | int idx = (int)(maxRiskProb*ts.length) - 1; 26 | if (idx >= 0) 27 | riskMark = ts[order[idx]]; 28 | 29 | return new double[]{riskProb,riskMark}; 30 | 31 | } 32 | 33 | //剔除ts中的负值,假定ts[0]为正值 34 | @Deprecated 35 | public static double[] evaRiskProb_v2(double[] ts, double maxRiskProb) { 36 | int[] order = Algorithm.bubbleSortAscending(ts); 37 | int negativeCount = 0; 38 | int pos = 0; 39 | for (int i = 0; i < order.length; i++) { 40 | if (ts[order[i]] < 0) 41 | negativeCount++; 42 | 43 | if (order[i] == 0) { 44 | pos = i; 45 | break; 46 | } 47 | } 48 | 49 | //当前风险概率水平 50 | double riskProb = (pos+1-negativeCount)/(double)(order.length-negativeCount); 51 | //满足风险条件的水位 52 | double riskMark = 0d; 53 | int idx = (int)(maxRiskProb*(ts.length-negativeCount)) - 1; 54 | if (idx >= 0) 55 | riskMark = ts[order[idx+negativeCount]]; 56 | 57 | return new double[]{riskProb,riskMark}; 58 | 59 | } 60 | 61 | 62 | /** 63 | * 计算PE, PB等风险指标的风险水位 64 | * @param ts 65 | * @param x 66 | * @return 67 | */ 68 | public static double calcRiskProb(double[] ts, double x) { 69 | double riskProb = Double.NaN; 70 | int pos = 0; 71 | for (int i = 0; i < ts.length; i++) 72 | if (ts[i] < x) { 73 | pos++; 74 | } 75 | 76 | //当前风险概率水平 77 | riskProb = (pos+1)/(double)ts.length; 78 | 79 | return riskProb; 80 | 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/diffwind/util/ThreadPoolExecutorManager.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.util; 2 | 3 | import java.util.concurrent.BlockingQueue; 4 | import java.util.concurrent.LinkedBlockingQueue; 5 | import java.util.concurrent.ThreadPoolExecutor; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | public class ThreadPoolExecutorManager { 9 | 10 | public static int poolSize = 4; 11 | public final static BlockingQueue workQueue = new LinkedBlockingQueue(100); 12 | public final static ThreadPoolExecutor executor = new ThreadPoolExecutor(poolSize, poolSize, 10, TimeUnit.SECONDS, workQueue); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/resources/config.properties: -------------------------------------------------------------------------------- 1 | # 通达信日线文件目录 2 | # 许多券商软件都使用通达信定制 3 | # 如使用招商证券软件Windows下文件目录为: 4 | # C:/zd_zszq/vipdoc/ 5 | sh.day.path=/Users/zhangjz/DiffWind.data/vipdoc/sh/lday/ 6 | sz.day.path=/Users/zhangjz/DiffWind.data/vipdoc/sz/lday/ 7 | -------------------------------------------------------------------------------- /src/main/resources/jdbc.properties: -------------------------------------------------------------------------------- 1 | jdbc.driverClassName=org.postgresql.Driver 2 | jdbc.url=jdbc:postgresql://localhost:5432/diffview 3 | jdbc.username=diffview 4 | jdbc.password=diffview 5 | -------------------------------------------------------------------------------- /src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | ## LOGGERS ## 2 | #log4j.rootLogger=DEBUG,console,file 3 | log4j.rootLogger=INFO,console,file 4 | 5 | log4j.logger.com.ibatis = WARN 6 | log4j.logger.com.ibatis.common.jdbc.SimpleDataSource = WARN 7 | log4j.logger.com.ibatis.common.jdbc.ScriptRunner = WARN 8 | log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate = WARN 9 | log4j.logger.java.sql.Connection = WARN 10 | log4j.logger.java.sql.Statement = WARN 11 | log4j.logger.java.sql.PreparedStatement = WARN 12 | log4j.logger.java.sql.ResultSet = WARN 13 | 14 | 15 | ## APPENDERS ## 16 | log4j.appender.console=org.apache.log4j.ConsoleAppender 17 | 18 | log4j.appender.file=org.apache.log4j.DailyRollingFileAppender 19 | log4j.appender.file.File=/Users/zhangjz/projects/DiffWind.logs/quant.log 20 | 21 | ## LAYOUTS ## 22 | log4j.appender.console.layout=org.apache.log4j.PatternLayout 23 | log4j.appender.console.layout.ConversionPattern=[%-5p][%d{yyyy-MM-dd HH:mm:ss}][%t] (%C{1}) %m%n 24 | 25 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 26 | log4j.appender.file.layout.ConversionPattern=[%-5p][%d{yyyy-MM-dd HH:mm:ss}][%t] (%C{1}) %m%n 27 | -------------------------------------------------------------------------------- /src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 30 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 40 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/main/resources/mybatis-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /src/main/sqlscripts/DBscripts: -------------------------------------------------------------------------------- 1 | # mac 2 | #pg_ctl start -D /u01/pgdata 3 | pg_ctl start 4 | 5 | -- pg_dump 6 | pg_dump diffview > /Users/zhangjz/diffview.dump 7 | psql diffview < diffview.dump 8 | psql --set ON_ERROR_STOP=on dbname < infile 9 | 10 | $ pg_dump -Fc diffview > /Users/zhangjz/diffview.dump 11 | $ pg_restore -d diffview diffview.dump 12 | 13 | 14 | # windows 15 | initdb -E UTF-8 -D D:\postgresql-10.0-1-windows-x64-binaries\pgsql\data --locale=Chinese_China 16 | -- create db 17 | createdb diffview 18 | dropdb diffview 19 | -- create role 20 | CREATE ROLE diffview LOGIN PASSWORD 'diffview'; 21 | GRANT ALL PRIVILEGES ON DATABASE diffview to diffview ; 22 | -- connect 23 | psql -d diffview 24 | -- start 25 | cd D:\postgresql-10.0-1-windows-x64-binaries\pgsql\bin 26 | pg_ctl start -D D:\postgresql-10.0-1-windows-x64-binaries\pgsql\data 27 | pg_ctl stop -D D:\postgresql-10.0-1-windows-x64-binaries\pgsql\data 28 | 29 | -------------------------------------------------------------------------------- /src/main/sqlscripts/eastmoney_tables.sql: -------------------------------------------------------------------------------- 1 | -- 融资融券 2 | -- drop table eastmoney_stock_rzrq; 3 | create table eastmoney_stock_rzrq_json 4 | ( 5 | "rzrq_data" jsonb 6 | ); 7 | 8 | -- 报表预约披露时间 9 | create table eastmoney_stock_bbsj 10 | ( 11 | "symbol" char(8), 12 | "code" char(6), 13 | "yuyue_date" date, 14 | "pilu_date" date, 15 | "finance_date" date 16 | ); 17 | 18 | 19 | -- 融资融券余额差值 20 | select rzrq_data->'rzrqyecz' from eastmoney_stock_rzrq_json 21 | where rzrq_data->>'tdate' = '2017-10-19T00:00:00'; 22 | -- 23 | select (rzrq_data->>'tdate')::date "交易日期",rzrq_data->'rzrqyecz' "融资融券余额差值" 24 | from eastmoney_stock_rzrq_json 25 | where rzrq_data->>'scode' = '600104' 26 | order by rzrq_data->>'tdate' desc; 27 | -- 28 | select (e.rzrq_data->>'tdate')::date "date", e.rzrq_data->'rzrqyecz' "rzrqyecz", x.close 29 | from eastmoney_stock_rzrq_json e left join xueqiu_stock_day_fq x 30 | on (e.rzrq_data->>'scode' = substr(x.symbol,3) and (e.rzrq_data->>'tdate')::date = x.date) 31 | where rzrq_data->>'scode' = '002142' 32 | order by rzrq_data->>'tdate' desc; 33 | 34 | -- 35 | delete from eastmoney_stock_rzrq_json 36 | where rzrq_data->>'scode' in ('510900', '601166', '601318', '000725', '601668', '600016', '600030', '002230', '600516', '000413', '600000', '002450', '600340', '300104', '601688', '600519', '601398', '000001', '600036', '000776', '600383', '000728', '600100', '600570', '002340', '600606', '600260', '600048', '601099', '600522', '000100', '600887', '000050', '601288', '601328', '601377', '601788', '000917', '600489', '300024', '300070', '601818', '600150', '002407', '000002', '300077', '600518', '600490', '000401', '002500', '601169', '000778', '002008', '600104', '601390', '000938', '600125', '601238', '600176', '300079', '600895', '000157', '002067', '601998', '601336', '600827', '002292', '600777', '000598', '600312', '600183', '600116', '002055', '600874', '000969', '601601', '000718', '300199', '600751', '300251', '600037', '600422', '000031', '000877', '002701', '603000', '000572', '601155', '000563', '600652', '002396', '002004', '600018', '000551', '002029', '600692', '600300', '600801', '601866', '600107', '002399', '002095', '002051', '600449', '600470', '600664', '002294', '600604', '600741', '600061', '600743', '000506', '600835', '300191', '600730', '002140', '002646', '000883', '002242', '600802', '601880', '600855', '000869', '601996', '002204', '600761', '000732', '600600', '512070'); 37 | -------------------------------------------------------------------------------- /src/main/sqlscripts/index.sql: -------------------------------------------------------------------------------- 1 | drop index idx1_tdx_stock_day; 2 | drop index idx2_tdx_stock_day; 3 | -- 创建索引的性能很差 (collate default) 4 | create index idx1_tdx_stock_day on tdx_stock_day (symbol); 5 | -- 创建索引的性能提高很多倍,因此英文字段表定义时使用collate "C" 6 | create index idx1_tdx_stock_day on tdx_stock_day (symbol collate "C"); 7 | 8 | 9 | create index idx2_tdx_stock_day on tdx_stock_day (date); 10 | 11 | 12 | CREATE INDEX "idx2_diffvalue_stock_stats_d" ON "public"."diffvalue_stock_stats_d" (lower(symbol)); 13 | CREATE INDEX "idx3_diffvalue_stock_stats_d" ON "public"."diffvalue_stock_stats_d" (date); 14 | 15 | -- TODO:symbol统一成小写 16 | CREATE INDEX "idx3_xueqiu_stock_day_fq" ON "public"."xueqiu_stock_day_fq" (upper(symbol)); 17 | -------------------------------------------------------------------------------- /src/main/sqlscripts/sina_tables.sql: -------------------------------------------------------------------------------- 1 | create table sina_stock 2 | ( 3 | "symbol" char(8) primary key, 4 | "code" char(6), 5 | "name" varchar(20) 6 | ); 7 | 8 | -- 9 | create table sina_zjhhangye 10 | ( 11 | "code" varchar(20), 12 | "name" varchar(120) 13 | ); 14 | 15 | create table sina_zjhhangye_stock 16 | ( 17 | "hycode" varchar(20), 18 | "hyname" varchar(120), 19 | "symbol" char(8), 20 | "name" varchar(20) 21 | ); 22 | 23 | -- 公司简介信息 24 | create table sina_stock_corp_info 25 | ( 26 | "symbol" char(8) primary key, 27 | "corp_name" varchar(60), 28 | "shangshi_date" date, 29 | "chengli_date" date, 30 | "zuzhixingshi" varchar(30), 31 | "history_names" varchar(200), 32 | "zhuce_addr" varchar(200), 33 | "bangong_addr" varchar(200), 34 | "jianjie" text, 35 | "jingyingfanwei" text 36 | ); 37 | 38 | -------------------------------------------------------------------------------- /src/main/sqlscripts/tdx_tables.sql: -------------------------------------------------------------------------------- 1 | -- 2 | create table tdx_stock_day( 3 | "symbol" char(8), 4 | "date" date, 5 | "open" double precision, 6 | "high" double precision, 7 | "low" double precision, 8 | "close" double precision, 9 | "amt" double precision, 10 | "vol" double precision 11 | ); 12 | 13 | -- tdx_stock_day使用分区表,每5年一个分区 14 | -- 使用PG继承表,不是严格意义上的分区表 -- 15 | 16 | -- 创建表分区 17 | CREATE TABLE IF NOT EXISTS "tdx_stock_day_2016-2020" ( 18 | check ("date" between '2016-01-01' and '2020-12-31') 19 | ) inherits (tdx_stock_day); 20 | CREATE TABLE IF NOT EXISTS "tdx_stock_day_2011-2015" ( 21 | check ("date" between '2011-01-01' and '2015-12-31') 22 | ) inherits (tdx_stock_day); 23 | CREATE TABLE IF NOT EXISTS "tdx_stock_day_2006-2010" ( 24 | check ("date" between '2006-01-01' and '2010-12-31') 25 | ) inherits (tdx_stock_day); 26 | CREATE TABLE IF NOT EXISTS "tdx_stock_day_2001-2005" ( 27 | check ("date" between '2001-01-01' and '2005-12-31') 28 | ) inherits (tdx_stock_day); 29 | 30 | 31 | -- 创建索引 32 | create index idx1_tdx_stock_day_2016-2020 on tdx_stock_day_2016-2020("symbol"); 33 | create index idx2_tdx_stock_day_2016-2020 on tdx_stock_day_2016-2020("date"); 34 | 35 | create index "idx1_tdx_stock_day_2011-2015" on "tdx_stock_day_2011-2015"("symbol"); 36 | create index idx2_tdx_stock_day_2011-2015 on tdx_stock_day_2011-2015("date"); 37 | -------------------------------------------------------------------------------- /src/main/sqlscripts/xueqiu_tables.sql: -------------------------------------------------------------------------------- 1 | create table xueqiu_stock 2 | ( 3 | "symbol" char(8) primary key, 4 | "code" char(6), 5 | "name" varchar(20) 6 | ); 7 | 8 | -- 9 | drop table xueqiu_stock_finance; 10 | create table xueqiu_stock_finance 11 | ( 12 | "symbol" char(8), 13 | "name" varchar(20), 14 | "reportdate" date, 15 | "basiceps" double precision, 16 | "epsdiluted" double precision, 17 | "epsweighted" double precision, 18 | "naps" double precision, 19 | "opercashpershare" double precision, 20 | "peropecashpershare" double precision, 21 | "netassgrowrate" double precision, 22 | "dilutedroe" double precision, 23 | "weightedroe" double precision, 24 | "mainbusincgrowrate" double precision, 25 | "netincgrowrate" double precision, 26 | "totassgrowrate" double precision, 27 | "salegrossprofitrto" double precision, 28 | "mainbusiincome" double precision, 29 | "mainbusiprofit" double precision, 30 | "totprofit" double precision, 31 | "netprofit" double precision, 32 | "totalassets" double precision, 33 | "totalliab" double precision, 34 | "totsharequi" double precision, 35 | "operrevenue" double precision, 36 | "invnetcashflow" double precision, 37 | "finnetcflow" double precision, 38 | "chgexchgchgs" double precision, 39 | "cashnetr" double precision, 40 | "cashequfinbal" double precision 41 | ); 42 | -- 43 | create index idx1_xueqiu_stock_finance on xueqiu_stock_finance(symbol); 44 | create index idx2_xueqiu_stock_finance on xueqiu_stock_finance(reportdate); 45 | 46 | 47 | -- add 20160530 48 | create table xueqiu_stock_shareschg 49 | ( 50 | "symbol" char(8), 51 | "publishdate" date, 52 | "begindate" date, 53 | "totalshare" double precision, 54 | "totalsharechg" double precision, 55 | "skchgexp" varchar(250), 56 | "fcircskamt" double precision, 57 | "circskamt" double precision, 58 | "ncircamt" double precision 59 | ); 60 | create index idx1_xueqiu_stock_shareschg on xueqiu_stock_shareschg(symbol); 61 | create index idx2_xueqiu_stock_shareschg on xueqiu_stock_shareschg(begindate); 62 | 63 | create table xueqiu_stock_income_statement_json 64 | ( 65 | "data" jsonb 66 | ); 67 | 68 | -------------------------------------------------------------------------------- /src/test/java/com/diffwind/dao/QueryMapperTest.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao; 2 | 3 | import java.io.IOException; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.concurrent.atomic.AtomicInteger; 8 | 9 | import org.apache.ibatis.io.Resources; 10 | import org.apache.ibatis.session.SqlSession; 11 | import org.apache.ibatis.session.SqlSessionFactory; 12 | import org.apache.ibatis.session.SqlSessionFactoryBuilder; 13 | import org.apache.log4j.Logger; 14 | import org.junit.Test; 15 | 16 | import com.diffwind.dao.mapper.EastmoneyStockRzrqJsonMapper; 17 | import com.diffwind.dao.mapper.QueryMapper; 18 | import com.diffwind.dao.mapper.SinaStockMapper; 19 | import com.diffwind.dao.mapper.TruncateTableMapper; 20 | import com.diffwind.dao.model.EastmoneyStockRzrqJson; 21 | import com.diffwind.dao.model.SinaStock; 22 | 23 | public class QueryMapperTest { 24 | 25 | private static Logger logger = Logger.getLogger(QueryMapperTest.class); 26 | 27 | private static SqlSessionFactory sqlSessionFactory = null; 28 | // private static SqlSessionFactory batchSqlSessionFactory = null; 29 | 30 | private static AtomicInteger finishedNum = new AtomicInteger(); 31 | 32 | private static List allStocks = null; 33 | 34 | static { 35 | // SqlSessionFactory sessionFactory = null; 36 | String resource = "mybatis-config.xml"; 37 | try { 38 | sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource),"simpleds"); 39 | 40 | SqlSession sqlSession = sqlSessionFactory.openSession(true); 41 | SinaStockMapper sinaStockMapper = sqlSession.getMapper(SinaStockMapper.class); 42 | allStocks = sinaStockMapper.selectAll(); 43 | sqlSession.close(); 44 | 45 | } catch (IOException e) { 46 | logger.error("mybatis config error", e); 47 | throw new RuntimeException("mybatis config error", e); 48 | } 49 | } 50 | 51 | 52 | //sh600104历史复权之后为负值,参考2006之前及2008 53 | @Test 54 | public void test() { 55 | 56 | SqlSession sqlSession = null; 57 | try { 58 | sqlSession = sqlSessionFactory.openSession(true); 59 | 60 | QueryMapper queryMapper = sqlSession.getMapper(QueryMapper.class); 61 | 62 | List symbols = Arrays.asList("sh600000", "sh601009"); 63 | 64 | List result = queryMapper.selectBySuodeshui_JinRong(symbols); 65 | 66 | List symbols2 = Arrays.asList("sz000069", "sh600566"); 67 | 68 | List result2 = queryMapper.selectBySuodeshui(symbols2); 69 | 70 | logger.info("测试结束"); 71 | } catch (Exception e) { 72 | logger.error("转存表sina_stock_xq_info失败", e); 73 | 74 | sqlSession.rollback(); 75 | } finally { 76 | sqlSession.close(); 77 | } 78 | 79 | } 80 | 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/test/java/com/diffwind/dao/TruncateTableMapperTest.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.dao; 2 | 3 | import java.io.IOException; 4 | import java.util.List; 5 | import java.util.concurrent.atomic.AtomicInteger; 6 | 7 | import org.apache.ibatis.io.Resources; 8 | import org.apache.ibatis.session.SqlSession; 9 | import org.apache.ibatis.session.SqlSessionFactory; 10 | import org.apache.ibatis.session.SqlSessionFactoryBuilder; 11 | import org.apache.log4j.Logger; 12 | import org.junit.Test; 13 | 14 | import com.diffwind.dao.mapper.EastmoneyStockRzrqJsonMapper; 15 | import com.diffwind.dao.mapper.SinaStockMapper; 16 | import com.diffwind.dao.mapper.TruncateTableMapper; 17 | import com.diffwind.dao.model.EastmoneyStockRzrqJson; 18 | import com.diffwind.dao.model.SinaStock; 19 | 20 | public class TruncateTableMapperTest { 21 | 22 | private static Logger logger = Logger.getLogger(TruncateTableMapperTest.class); 23 | 24 | private static SqlSessionFactory sqlSessionFactory = null; 25 | // private static SqlSessionFactory batchSqlSessionFactory = null; 26 | 27 | private static AtomicInteger finishedNum = new AtomicInteger(); 28 | 29 | private static List allStocks = null; 30 | 31 | static { 32 | // SqlSessionFactory sessionFactory = null; 33 | String resource = "mybatis-config.xml"; 34 | try { 35 | sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource),"simpleds"); 36 | 37 | SqlSession sqlSession = sqlSessionFactory.openSession(true); 38 | SinaStockMapper sinaStockMapper = sqlSession.getMapper(SinaStockMapper.class); 39 | allStocks = sinaStockMapper.selectAll(); 40 | sqlSession.close(); 41 | 42 | } catch (IOException e) { 43 | logger.error("mybatis config error", e); 44 | throw new RuntimeException("mybatis config error", e); 45 | } 46 | } 47 | 48 | 49 | //sh600104历史复权之后为负值,参考2006之前及2008 50 | @Test 51 | public void test() { 52 | 53 | SqlSession sqlSession = null; 54 | try { 55 | sqlSession = sqlSessionFactory.openSession(true); 56 | 57 | TruncateTableMapper truncateTableMapper = sqlSession.getMapper(TruncateTableMapper.class); 58 | 59 | truncateTableMapper.swapTable("sina_stock_xq_info"); 60 | 61 | } catch (Exception e) { 62 | logger.error("转存表sina_stock_xq_info失败", e); 63 | 64 | sqlSession.rollback(); 65 | } finally { 66 | sqlSession.close(); 67 | } 68 | 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/test/java/com/diffwind/data/EastmoneyStockRzrqJsonTest.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.data; 2 | 3 | import java.io.IOException; 4 | import java.util.List; 5 | import java.util.concurrent.atomic.AtomicInteger; 6 | 7 | import org.apache.ibatis.io.Resources; 8 | import org.apache.ibatis.session.SqlSession; 9 | import org.apache.ibatis.session.SqlSessionFactory; 10 | import org.apache.ibatis.session.SqlSessionFactoryBuilder; 11 | import org.apache.log4j.Logger; 12 | import org.junit.Test; 13 | 14 | import com.diffwind.dao.mapper.EastmoneyStockRzrqJsonMapper; 15 | import com.diffwind.dao.mapper.SinaStockMapper; 16 | import com.diffwind.dao.model.EastmoneyStockRzrqJson; 17 | import com.diffwind.dao.model.SinaStock; 18 | 19 | public class EastmoneyStockRzrqJsonTest { 20 | 21 | private static Logger logger = Logger.getLogger(EastmoneyStockRzrqJsonTest.class); 22 | 23 | private static SqlSessionFactory sqlSessionFactory = null; 24 | // private static SqlSessionFactory batchSqlSessionFactory = null; 25 | 26 | private static AtomicInteger finishedNum = new AtomicInteger(); 27 | 28 | private static List allStocks = null; 29 | 30 | static { 31 | // SqlSessionFactory sessionFactory = null; 32 | String resource = "mybatis-config.xml"; 33 | try { 34 | sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(resource),"simpleds"); 35 | 36 | SqlSession sqlSession = sqlSessionFactory.openSession(true); 37 | SinaStockMapper sinaStockMapper = sqlSession.getMapper(SinaStockMapper.class); 38 | allStocks = sinaStockMapper.selectAll(); 39 | sqlSession.close(); 40 | 41 | } catch (IOException e) { 42 | logger.error("mybatis config error", e); 43 | throw new RuntimeException("mybatis config error", e); 44 | } 45 | } 46 | 47 | 48 | //sh600104历史复权之后为负值,参考2006之前及2008 49 | @Test 50 | public void test() { 51 | 52 | SqlSession sqlSession = null; 53 | String symbol = "sh600104"; 54 | try { 55 | sqlSession = sqlSessionFactory.openSession(true); 56 | EastmoneyStockRzrqJsonMapper eastmoneyStockRzrqJsonMapper = sqlSession.getMapper(EastmoneyStockRzrqJsonMapper.class); 57 | 58 | 59 | List result = eastmoneyStockRzrqJsonMapper.selectAll(); 60 | 61 | System.out.print(result.get(0).getRzrqData()); 62 | 63 | } catch (Exception e) { 64 | logger.error("find出错: " + symbol, e); 65 | } finally { 66 | sqlSession.close(); 67 | } 68 | 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/test/java/com/diffwind/stats/JRIChartTest.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.stats; 2 | 3 | import org.junit.Test; 4 | import org.rosuda.JRI.Rengine; 5 | 6 | public class JRIChartTest { 7 | 8 | @Test 9 | public void testStats_D() { 10 | 11 | String symbol = "SZ00528"; 12 | 13 | 14 | Rengine re = new Rengine(new String[] { "--vanilla" }, false, null); 15 | System.out.println("Rengine created, waiting for R"); 16 | 17 | // the engine creates R is a new thread, so we should wait until it's 18 | // ready 19 | if (!re.waitForR()) { 20 | System.out.println("Cannot load R"); 21 | return; 22 | } 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/diffwind/stats/MemStatsStockDayTest.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.stats; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | import org.junit.Test; 7 | 8 | import com.alibaba.fastjson.JSON; 9 | import com.alibaba.fastjson.serializer.SerializerFeature; 10 | import com.diffwind.stats.MemStatsStockDay; 11 | import com.diffwind.stats.StockDayViewWind; 12 | import com.diffwind.stats.StockQuarterViewWind; 13 | import com.diffwind.util.DateUtil; 14 | 15 | public class MemStatsStockDayTest { 16 | 17 | @Test 18 | public void test() { 19 | //sz300317复权计算结果遗漏了2015-07-07 20 | //String symbol = "sz300317"; 21 | String symbol = "sz000625"; 22 | //String symbol = "sh600011"; 23 | //String symbol = "sz002152"; 24 | StockDayViewWind stockDayViewWind = MemStatsStockDay.stats(symbol); 25 | //测试 26 | //JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd"; 27 | //System.out.print(JSON.toJSONString(stockDayViewWind,SerializerFeature.WriteDateUseDateFormat)); 28 | 29 | String[] date = stockDayViewWind.dayViewHist.stream().map(obj -> DateUtil.yyyyMMdd10.get().format(obj.getDate())).toArray(String[]::new); 30 | System.out.println("Date: " + Arrays.toString(date)); 31 | double[] pe1Y = stockDayViewWind.dayViewHist.stream().mapToDouble(obj -> obj.getPe1Y()).toArray(); 32 | System.out.println("PE1Y: " + Arrays.toString(pe1Y)); 33 | double[] pe4Q = stockDayViewWind.dayViewHist.stream().mapToDouble(obj -> obj.getPe4Q()).toArray(); 34 | System.out.println("PE4Q: " + Arrays.toString(pe4Q)); 35 | 36 | 37 | String[] reportDate = stockDayViewWind.financeChgHistWind.financeChgHist.stream().map(obj -> DateUtil.yyyyMMdd10.get().format(obj.getReportDate())).toArray(String[]::new); 38 | System.out.println("Report Date: " + Arrays.toString(reportDate)); 39 | 40 | double[] eps1Y = stockDayViewWind.financeChgHistWind.financeChgHist.stream().mapToDouble(obj -> obj.getEps1Y()).toArray(); 41 | System.out.println("EPS1Y: " + Arrays.toString(eps1Y)); 42 | 43 | 44 | double[] close = stockDayViewWind.dayViewHist.stream().mapToDouble(obj -> obj.getClose()).toArray(); 45 | 46 | System.out.println(Arrays.toString(close)); 47 | 48 | double[] fqClose = stockDayViewWind.dayViewHist.stream().mapToDouble(obj -> obj.getFqClose()).toArray(); 49 | 50 | System.out.println(Arrays.toString(fqClose)); 51 | } 52 | 53 | 54 | @Test 55 | public void test2() { 56 | 57 | String symbol = "sz000625"; 58 | StockDayViewWind stockDayViewWind = MemStatsStockDay.stats(symbol); 59 | 60 | System.out.println(stockDayViewWind.financeChgHistWind); 61 | } 62 | 63 | 64 | @Test 65 | public void test3() { 66 | //String symbol = "sz000625"; 67 | String symbol = "sz300255"; 68 | 69 | //sz300255股本变更数据新浪与雪球不一致2016-08-16 雪球变动日为2016-08-17新浪变动日为2016-08-18 70 | 71 | StockDayViewWind stockDayViewWind = MemStatsStockDay.stats(symbol); 72 | StockQuarterViewWind financeQuarterHist = stockDayViewWind.financeChgHistWind; 73 | //测试 74 | //JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd"; 75 | //System.out.print(JSON.toJSONString(financeQuarterHist.financeChgHist,SerializerFeature.WriteDateUseDateFormat)); 76 | 77 | /* 78 | String[] reportDate = financeQuarterHist.financeChgHist.stream().map(obj -> DateUtil.yyyyMMdd10.get().format(obj.getReportDate())).toArray(String[]::new); 79 | System.out.println(Arrays.toString(reportDate)); 80 | 81 | String[] reportQuarter = financeQuarterHist.quarterFinanceHist.stream().map(obj -> DateUtil.yyyyMMdd10.get().format(obj.getReportDate())).toArray(String[]::new); 82 | System.out.println(Arrays.toString(reportQuarter)); 83 | 84 | String[] reportYear = financeQuarterHist.yearFinanceHist.stream().map(obj -> DateUtil.yyyyMMdd10.get().format(obj.getReportDate())).toArray(String[]::new); 85 | System.out.println(Arrays.toString(reportYear)); 86 | */ 87 | System.out.print(financeQuarterHist); 88 | 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/test/java/com/diffwind/stats/MemStatsStockQuarterTest.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.stats; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | import org.junit.Test; 7 | 8 | import com.alibaba.fastjson.JSON; 9 | import com.alibaba.fastjson.serializer.SerializerFeature; 10 | import com.diffwind.stats.MemStatsStockQuarter; 11 | import com.diffwind.stats.StockQuarterViewWind; 12 | import com.diffwind.util.DateUtil; 13 | 14 | public class MemStatsStockQuarterTest { 15 | 16 | @Test 17 | public void test() { 18 | //String symbol = "sz000625"; 19 | //String symbol = "sz300255"; 20 | String symbol = "sz000513"; 21 | 22 | StockQuarterViewWind financeQuarterHist = MemStatsStockQuarter.stats(symbol); 23 | //测试 24 | //JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd"; 25 | //System.out.print(JSON.toJSONString(financeQuarterHist.financeChgHist,SerializerFeature.WriteDateUseDateFormat)); 26 | 27 | String[] reportDate = financeQuarterHist.financeChgHist.stream().map(obj -> DateUtil.yyyyMMdd10.get().format(obj.getReportDate())).toArray(String[]::new); 28 | System.out.println(Arrays.toString(reportDate)); 29 | 30 | String[] reportQuarter = financeQuarterHist.quarterFinanceHist.stream().map(obj -> DateUtil.yyyyMMdd10.get().format(obj.getReportDate())).toArray(String[]::new); 31 | System.out.println(Arrays.toString(reportQuarter)); 32 | 33 | String[] reportYear = financeQuarterHist.yearFinanceHist.stream().map(obj -> DateUtil.yyyyMMdd10.get().format(obj.getReportDate())).toArray(String[]::new); 34 | System.out.println(Arrays.toString(reportYear)); 35 | 36 | double[] EBIT = financeQuarterHist.quarterFinanceHist.stream().mapToDouble(obj -> obj.getEBIT()).toArray(); 37 | System.out.println(Arrays.toString(EBIT)); 38 | 39 | double[] EBIT4Q = financeQuarterHist.quarterFinanceHist.stream().mapToDouble(obj -> obj.getEBIT4Q()).toArray(); 40 | System.out.println(Arrays.toString(EBIT4Q)); 41 | } 42 | 43 | @Test 44 | public void roundTest() { 45 | //以下结果不一样 46 | System.out.println(Math.round(401.5)); 47 | System.out.println(Math.round(4.015*100)); 48 | System.out.println(4.015*100); 49 | 50 | //以下结果不一样,double类型只要做运算,结果就可能不精确 51 | double abc = 4.5; //4.025 52 | System.out.println(abc); 53 | System.out.println(Double.toString(abc)); 54 | System.out.println(new java.math.BigDecimal(abc).setScale(2,java.math.BigDecimal.ROUND_HALF_UP)); 55 | System.out.println(new java.math.BigDecimal("4.015").setScale(2,java.math.BigDecimal.ROUND_HALF_UP)); 56 | 57 | 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/test/java/com/diffwind/util/CalendarTest.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.util; 2 | 3 | import java.text.ParseException; 4 | import java.util.Calendar; 5 | import java.util.Date; 6 | 7 | import org.junit.Test; 8 | 9 | import com.diffwind.util.DateUtil; 10 | 11 | public class CalendarTest { 12 | 13 | @Test 14 | public void testMonth() throws ParseException { 15 | 16 | Date date = DateUtil.yyyyMMdd10.get().parse("2017-12-31"); 17 | Calendar cal = Calendar.getInstance(); 18 | cal.setTime(date); 19 | 20 | cal.add(Calendar.MONTH, 4); 21 | 22 | System.out.println(DateUtil.yyyyMMdd10.get().format(cal.getTime()) ); 23 | 24 | for (int i = 1; i < 20; i++) { 25 | cal.add(Calendar.MONTH, 1); 26 | 27 | System.out.println(DateUtil.yyyyMMdd10.get().format(cal.getTime()) ); 28 | } 29 | 30 | 31 | 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/com/diffwind/util/FunctionsTest.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.util; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.junit.Test; 6 | 7 | import com.diffwind.util.Functions; 8 | 9 | public class FunctionsTest { 10 | 11 | @Test 12 | public void test() { 13 | //312 445.74 11.49 14 | int days = 312; 15 | double R = 4.4574; 16 | double r = Functions.simR2logR(R); 17 | double day_r = r/days; 18 | double day_R = Functions.logR2simR(day_r); 19 | 20 | double R2 = Math.pow((1+day_R), days) - 1; 21 | 22 | System.out.println(r); 23 | System.out.println(day_r); 24 | System.out.println(day_R); 25 | System.out.println(R2); 26 | 27 | double days20_R = Functions.calcDiffWindReturn(days, R, 20); 28 | System.out.println(days20_R); 29 | } 30 | 31 | 32 | @Test 33 | public void test2() { 34 | double[] ts = {10, 11, 11.5, 11.2, 12}; 35 | 36 | double[] cumsum0 = Functions.cumsum0(ts, -1); 37 | 38 | double[] cumsub0 = Functions.cumsub0(ts, 1); 39 | 40 | System.out.println(Arrays.toString(cumsum0)); 41 | System.out.println(Arrays.toString(cumsub0)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/com/diffwind/util/GregorianCalendarTest.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.util; 2 | 3 | import java.text.ParseException; 4 | import java.util.GregorianCalendar; 5 | 6 | import org.junit.Test; 7 | 8 | import com.diffwind.util.DateUtil; 9 | 10 | public class GregorianCalendarTest { 11 | 12 | @Test 13 | public void test() throws ParseException { 14 | GregorianCalendar gc = new GregorianCalendar(); 15 | gc.setTime(DateUtil.yyyyMMdd.get().parse("20170101")); 16 | gc.add(GregorianCalendar.DAY_OF_MONTH, -1); 17 | 18 | System.out.println(gc.getTime()); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/diffwind/util/StringUtilTest.java: -------------------------------------------------------------------------------- 1 | package com.diffwind.util; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.junit.Test; 6 | 7 | public class StringUtilTest { 8 | 9 | @Test 10 | public void splitTest() { 11 | //String record = "600201,生物股份,2008-04-08,,,,2008-04-08,2008-03-31"; 12 | String record = "600104,上汽集团,2016-10-29,,,,2016-10-29,2016-09-30"; 13 | String[] info = record.split(","); 14 | 15 | System.out.println(Arrays.toString(info)); 16 | } 17 | 18 | @Test 19 | public void replaceTest() { 20 | String s1 = "三、营业利润"; 21 | String s2 = "(二)稀释每股收益"; 22 | 23 | String ret = s1.replaceAll("一、|二、|三、|四、|五、|六、|七、|八、|九、|十、|(一)|(二)|(三)|(四)|(五)|(六)|(七)|(八)|(九)|(十)", ""); 24 | 25 | System.out.println(ret); 26 | 27 | ret = s2.replaceAll("一、|二、|三、|四、|五、|六、|七、|八、|九、|十、|\\(一\\)|\\(二\\)|\\(三\\)|\\(四\\)|\\(五\\)|\\(六\\)|\\(七\\)|\\(八\\)|\\(九\\)|\\(十\\)", ""); 28 | 29 | System.out.println(ret); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/sort/CollectionTest.java: -------------------------------------------------------------------------------- 1 | package sort; 2 | import java.util.ArrayList; 3 | import java.util.Collections; 4 | import java.util.Comparator; 5 | import java.util.List; 6 | 7 | /** 8 | * @date: 2015年6月19日 上午10:11:44 9 | */ 10 | 11 | public class CollectionTest { 12 | /** 13 | * 主方法 14 | * 15 | * @param args 16 | * 参数 17 | * @modify by user: {修改人} 2015年6月19日 18 | * @modify by reason:{原因} 19 | */ 20 | public static void main(String[] args) { 21 | List mans = new ArrayList(); 22 | CollectionTest collectionTest = new CollectionTest(); 23 | Man man = collectionTest.new Man(); 24 | man.setParentId(11); 25 | man.setAge(12); 26 | man.setName("某某1_孩子"); 27 | Man man2 = collectionTest.new Man(); 28 | man2.setParentId(2); 29 | man2.setAge(13); 30 | man2.setName("某某2_孩子"); 31 | Man man3 = collectionTest.new Man(); 32 | man3.setParentId(2); 33 | man3.setAge(16); 34 | man3.setName("某某1_孩子"); 35 | mans.add(man); 36 | mans.add(man2); 37 | mans.add(man3); 38 | sortAge(mans); 39 | System.out.println("*****根据年龄排序********"); 40 | System.out.println(mans.toString()); 41 | sortParentIdAge(mans); 42 | System.out.println("*****根据父ID,年龄排序********"); 43 | System.out.println(mans.toString()); 44 | } 45 | 46 | /** 47 | * 根据父ID,年龄进行排序 48 | * 49 | * @param mans 50 | * 人列表 51 | * @modify by user: {修改人} 2015年6月19日 52 | * @modify by reason:{原因} 53 | */ 54 | private static void sortParentIdAge(List mans) { 55 | Collections.sort(mans, new Comparator() { 56 | @Override 57 | public int compare(Man o1, Man o2) { 58 | if (o1.getParentId().equals(o2.getParentId())) { 59 | return o1.getAge().compareTo(o2.getAge()); 60 | } else { 61 | return o1.getParentId().compareTo(o2.getParentId()); 62 | } 63 | } 64 | }); 65 | } 66 | 67 | /** 68 | * 根据父ID排序 69 | * 70 | * @param mans 71 | * @modify by user: {修改人} 2015年6月19日 72 | * @modify by reason:{原因} 73 | */ 74 | private static void sortAge(List mans) { 75 | Collections.sort(mans, new Comparator() { 76 | @Override 77 | public int compare(Man o1, Man o2) { 78 | return o1.getAge().compareTo(o2.getAge()); 79 | } 80 | }); 81 | } 82 | 83 | public class Man { 84 | 85 | private Integer parentId; 86 | 87 | private Integer age; 88 | 89 | private String name; 90 | 91 | /** 92 | * 获取parentId 93 | * 94 | * @return parentId parentId 95 | */ 96 | public Integer getParentId() { 97 | return parentId; 98 | 99 | } 100 | 101 | /** 102 | * 设置parentId 103 | * 104 | * @param parentId 105 | * parentId 106 | */ 107 | public void setParentId(Integer parentId) { 108 | this.parentId = parentId; 109 | } 110 | 111 | /** 112 | * 获取age 113 | * 114 | * @return age age 115 | */ 116 | public Integer getAge() { 117 | return age; 118 | 119 | } 120 | 121 | /** 122 | * 设置age 123 | * 124 | * @param age 125 | * age 126 | */ 127 | public void setAge(Integer age) { 128 | this.age = age; 129 | } 130 | 131 | /** 132 | * 获取name 133 | * 134 | * @return name name 135 | */ 136 | public String getName() { 137 | return name; 138 | 139 | } 140 | 141 | /** 142 | * 设置name 143 | * 144 | * @param name 145 | * name 146 | */ 147 | public void setName(String name) { 148 | this.name = name; 149 | } 150 | 151 | /** 152 | * @return 153 | * @modify by user: {修改人} 2015年6月19日 154 | * @modify by reason:{原因} 155 | */ 156 | @Override 157 | public String toString() { 158 | return "Man [parentId=" + parentId + ", age=" + age + ", name=" + name + "]"; 159 | } 160 | 161 | } 162 | } 163 | --------------------------------------------------------------------------------