Browse Source

init finance

master
杨辉 1 year ago
parent
commit
c381eed309
  1. BIN
      .DS_Store
  2. BIN
      plugin-finance-function/.DS_Store
  3. 122
      plugin-finance-function/build.gradle
  4. BIN
      plugin-finance-function/build/.DS_Store
  5. BIN
      plugin-finance-function/build/install/fine-plugin-com.fr.plugin.function.finance-3.0.zip
  6. BIN
      plugin-finance-function/build/libs/fine-plugin-com.fr.plugin.function.finance-3.0.jar
  7. BIN
      plugin-finance-function/build/temp/plugin/fine-plugin-com.fr.plugin.function.finance-3.0.jar
  8. 85
      plugin-finance-function/build/temp/plugin/plugin.xml
  9. 2
      plugin-finance-function/build/tmp/makeJar/MANIFEST.MF
  10. 13
      plugin-finance-function/encrypt.xml
  11. 85
      plugin-finance-function/plugin.xml
  12. 48
      plugin-finance-function/readme.md
  13. BIN
      plugin-finance-function/src/.DS_Store
  14. BIN
      plugin-finance-function/src/main/.DS_Store
  15. 565
      plugin-finance-function/src/main/java/com/fr/plugin/DateUtil.java
  16. 60
      plugin-finance-function/src/main/java/com/fr/plugin/FV.java
  17. 10
      plugin-finance-function/src/main/java/com/fr/plugin/FinanceFinder.java
  18. 6
      plugin-finance-function/src/main/java/com/fr/plugin/FinanceFunctionConstants.java
  19. 29
      plugin-finance-function/src/main/java/com/fr/plugin/FinanceGroup.java
  20. 66
      plugin-finance-function/src/main/java/com/fr/plugin/IPMT.java
  21. 196
      plugin-finance-function/src/main/java/com/fr/plugin/IRR.java
  22. 112
      plugin-finance-function/src/main/java/com/fr/plugin/MIRR.java
  23. 62
      plugin-finance-function/src/main/java/com/fr/plugin/NPER.java
  24. 52
      plugin-finance-function/src/main/java/com/fr/plugin/NPV.java
  25. 82
      plugin-finance-function/src/main/java/com/fr/plugin/PMT.java
  26. 68
      plugin-finance-function/src/main/java/com/fr/plugin/PPMT.java
  27. 63
      plugin-finance-function/src/main/java/com/fr/plugin/PV.java
  28. 130
      plugin-finance-function/src/main/java/com/fr/plugin/Rate.java
  29. 111
      plugin-finance-function/src/main/java/com/fr/plugin/UpbaaDate.java
  30. 136
      plugin-finance-function/src/main/java/com/fr/plugin/XIRR.java
  31. 116
      plugin-finance-function/src/main/java/com/fr/plugin/XirrData.java
  32. 1
      plugin-finance-function/src/main/resources/com/fr/plugin/demo.properties
  33. 1
      plugin-finance-function/src/main/resources/com/fr/plugin/demo_zh_CN.properties

BIN
.DS_Store vendored

Binary file not shown.

BIN
plugin-finance-function/.DS_Store vendored

Binary file not shown.

122
plugin-finance-function/build.gradle

@ -0,0 +1,122 @@
apply plugin: 'java'
ext {
/**
* jar的路径
* 1.jar需要打包到zip中,lib根目录下
* 2.jar仅仅是编译时需要lib下子目录下即可
*/
libPath = "$projectDir/../webroot/WEB-INF/lib"
/**
* class进行加密保护
*/
guard = true
def pluginInfo = getPluginInfo()
pluginPre = "fine-plugin"
pluginName = pluginInfo.id
pluginVersion = pluginInfo.version
outputPath = "$projectDir/../webroot/WEB-INF/plugins/plugin-" + pluginName + "-1.0/classes"
}
group = 'com.fr.plugin'
version = '10.0'
sourceCompatibility = '8'
sourceSets {
main {
java.outputDir = file(outputPath)
output.resourcesDir = file(outputPath)
}
}
ant.importBuild("encrypt.xml")
//ant变量
ant.projectDir = projectDir
ant.references["compile.classpath"] = ant.path {
fileset(dir: libPath, includes: '**/*.jar')
fileset(dir: ".",includes:"**/*.jar" )
}
classes.dependsOn('clean')
task copyFiles(type: Copy,dependsOn: 'classes'){
from outputPath
into "$projectDir/classes"
}
task preJar(type:Copy,dependsOn: guard ? 'compile_encrypt_javas' : 'compile_plain_javas'){
from "$projectDir/classes"
into "$projectDir/transform-classes"
include "**/*.*"
}
jar.dependsOn("preJar")
task makeJar(type: Jar,dependsOn: preJar){
from fileTree(dir: "$projectDir/transform-classes")
baseName pluginPre
appendix pluginName
version pluginVersion
destinationDir = file("$buildDir/libs")
doLast(){
delete file("$projectDir/classes")
delete file("$projectDir/transform-classes")
}
}
task copyFile(type: Copy,dependsOn: ["makeJar"]){
from "$buildDir/libs"
from("$projectDir/lib") {
include "*.jar"
}
from "$projectDir/plugin.xml"
into file("$buildDir/temp/plugin")
}
task zip(type:Zip,dependsOn:["copyFile"]){
from "$buildDir/temp/plugin"
destinationDir file("$buildDir/install")
baseName pluginPre
appendix pluginName
version pluginVersion
}
//build时包含哪些文件,
processResources {
// exclude everything
// *.css没效果
// exclude '**/*.css'
// except this file
// include 'xx.xml'
}
/*读取plugin.xml中的version*/
def getPluginInfo(){
def xmlFile = file("plugin.xml")
if (!xmlFile.exists()) {
return ["id":"none", "version":"1.0.0"]
}
def plugin = new XmlParser().parse(xmlFile)
def version = plugin.version[0].text()
def id = plugin.id[0].text()
return ["id":id,"version":version]
}
repositories {
mavenLocal()
maven {
url = uri('http://mvn.finedevelop.com/repository/maven-public/')
}
}
dependencies {
//使jar
implementation fileTree(dir: 'lib', include: ['**/*.jar'])
implementation fileTree(dir: libPath, include: ['**/*.jar'])
}

BIN
plugin-finance-function/build/.DS_Store vendored

Binary file not shown.

BIN
plugin-finance-function/build/install/fine-plugin-com.fr.plugin.function.finance-3.0.zip

Binary file not shown.

BIN
plugin-finance-function/build/libs/fine-plugin-com.fr.plugin.function.finance-3.0.jar

Binary file not shown.

BIN
plugin-finance-function/build/temp/plugin/fine-plugin-com.fr.plugin.function.finance-3.0.jar

Binary file not shown.

85
plugin-finance-function/build/temp/plugin/plugin.xml

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><plugin>
<id>com.fr.plugin.function.finance</id>
<name><![CDATA[财务函数插件]]></name>
<active>yes</active>
<version>3.0</version>
<env-version>10.0~11.0</env-version>
<jartime>2020-04-01</jartime>
<vendor>yanghui</vendor>
<description><![CDATA[可以实现Excel中的财务公式]]></description>
<change-notes><![CDATA[
[2020-07-13]初始化插件。<br/>
]]>
<![CDATA[
[2020-11-28]新增PPMT,IPMT,PV,FV,NPV,NPER,MIRR函数。<br/>
]]>
<![CDATA[
[2021-09-11]环境支持10.0~11.0。<br/>
]]>
</change-notes>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.XIRR" name="XIRR" description="XIRR函数返回一组不一定定期发生的现金流的内部收益率:参数1为现金流数组,参数2为对应还款日期列表,参数3估计值为选填。"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.IRR" name="IRR" description="IRR函数返回由值中的数字表示的一系列现金流的内部收益率:参数1为现金流数组,参数2为估计值,参数2为选填,如果省略guess,则假定它为0.1。"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.PMT" name="PMT" description="PMT函数根据固定付款额和固定利率计算贷款的付款额:参数1为每期利率,参数2为贷款总期数,参数3现值pv即本金,参数4为未来值fv,参数5为付款时间是在期初还是期末,前三个参数必填,后面两个选填。"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.Rate" name="Rate" description="RATE函数返回年金每期的利率:参数1为贷款总期数,参数2为每期付款金额,参数3为付款金额的总和,参数4为未来值fv,参数5为type付款时间是在期初还是期末,参数6为预期利率,省略的话默认为0.1,前三个参数必填,后三个选填。"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.PV" name="PV" description="投资的现值PV:参数1为利率,参数2为总期数,参数3为每期付款金额,参数4未来值fv,参数5付款时间是在期初还是期末,前三个参数必填,后面两个选填"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.FV" name="FV" description="计算投资价值的函数FV:参数1为利率,参数2为总期数,参数3为每期付款金额,参数4现值pv,参数5每期付款时间是在期初还是期末,前三个参数必填,后面两个选填"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.NPV" name="NPV" description="使用贴现率和一系列未来支出(负值)和收益(正值)来计算一项投资的净现值NPV:参数1为利率,参数2为现金流,按正确的顺序输入支出值和收益值"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.NPER" name="NPER" description="基于固定利率及等额分期付款方式,返回某项投资的总期数NPER:参数1为各期利率,参数2为每期付款金额,参数3为现值pv,参数4未来值fv,参数5付款时间是在期初还是期末,前三个参数必填,后面两个选填"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.IPMT" name="IPMT" description="基于固定利率及等额分期付款方式,返回给定期数内对投资的利息偿还额函数IPMT:参数1为各期利率,参数2为用于计算其利息数额的期数,参数3为总期数,参数4现值pv,参数5未来值fv,参数6付款时间是在期初还是期末,前四个参数必填,后面两个选填"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.PPMT" name="PPMT" description="PPMT函数返回根据定期固定付款和固定利率而定的投资在已知期间内的本金偿付额:参数1为利率,参数2为期数,参数3为总期数,参数4现值pv,参数5为未来值fv,参数6付款时间是在期初还是期末,前四个参数必填,后面两个选填"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.MIRR" name="ppmt" description="MIRR函数返回一系列定期现金流的修改后内部收益率,同时考虑投资的成本和现金再投资的收益率:参数1为现金流数组,参数2为资金支付利率,参数3为再投资收益率。"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionGroup class="com.fr.plugin.FinanceGroup" />
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<function-recorder class="com.fr.plugin.IRR"/>
<function-recorder class="com.fr.plugin.PMT"/>
<function-recorder class="com.fr.plugin.Rate"/>
<function-recorder class="com.fr.plugin.PPMT"/>
<function-recorder class="com.fr.plugin.IPMT"/>
<function-recorder class="com.fr.plugin.PV"/>
<function-recorder class="com.fr.plugin.FV"/>
<function-recorder class="com.fr.plugin.NPV"/>
<function-recorder class="com.fr.plugin.XIRR"/>
<function-recorder class="com.fr.plugin.NPER"/>
<function-recorder class="com.fr.plugin.MIRR"/>
</plugin>

2
plugin-finance-function/build/tmp/makeJar/MANIFEST.MF

@ -0,0 +1,2 @@
Manifest-Version: 1.0

13
plugin-finance-function/encrypt.xml

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project>
<target name="compile_encrypt_javas" depends="copyFiles">
<echo message="加密文件"/>
<echo message="${projectDir}"/>
<taskdef name="pretreatment" classname="com.fr.plugin.pack.PluginPretreatmentTask">
<classpath refid="compile.classpath"/>
</taskdef>
<pretreatment baseDir="${projectDir}"/>
</target>
<target name="compile_plain_javas" depends="copyFiles">
</target>
</project>

85
plugin-finance-function/plugin.xml

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><plugin>
<id>com.fr.plugin.function.finance</id>
<name><![CDATA[财务函数插件]]></name>
<active>yes</active>
<version>3.0</version>
<env-version>10.0~11.0</env-version>
<jartime>2020-04-01</jartime>
<vendor>yanghui</vendor>
<description><![CDATA[可以实现Excel中的财务公式]]></description>
<change-notes><![CDATA[
[2020-07-13]初始化插件。<br/>
]]>
<![CDATA[
[2020-11-28]新增PPMT,IPMT,PV,FV,NPV,NPER,MIRR函数。<br/>
]]>
<![CDATA[
[2021-09-11]环境支持10.0~11.0。<br/>
]]>
</change-notes>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.XIRR" name="XIRR" description="XIRR函数返回一组不一定定期发生的现金流的内部收益率:参数1为现金流数组,参数2为对应还款日期列表,参数3估计值为选填。"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.IRR" name="IRR" description="IRR函数返回由值中的数字表示的一系列现金流的内部收益率:参数1为现金流数组,参数2为估计值,参数2为选填,如果省略guess,则假定它为0.1。"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.PMT" name="PMT" description="PMT函数根据固定付款额和固定利率计算贷款的付款额:参数1为每期利率,参数2为贷款总期数,参数3现值pv即本金,参数4为未来值fv,参数5为付款时间是在期初还是期末,前三个参数必填,后面两个选填。"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.Rate" name="Rate" description="RATE函数返回年金每期的利率:参数1为贷款总期数,参数2为每期付款金额,参数3为付款金额的总和,参数4为未来值fv,参数5为type付款时间是在期初还是期末,参数6为预期利率,省略的话默认为0.1,前三个参数必填,后三个选填。"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.PV" name="PV" description="投资的现值PV:参数1为利率,参数2为总期数,参数3为每期付款金额,参数4未来值fv,参数5付款时间是在期初还是期末,前三个参数必填,后面两个选填"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.FV" name="FV" description="计算投资价值的函数FV:参数1为利率,参数2为总期数,参数3为每期付款金额,参数4现值pv,参数5每期付款时间是在期初还是期末,前三个参数必填,后面两个选填"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.NPV" name="NPV" description="使用贴现率和一系列未来支出(负值)和收益(正值)来计算一项投资的净现值NPV:参数1为利率,参数2为现金流,按正确的顺序输入支出值和收益值"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.NPER" name="NPER" description="基于固定利率及等额分期付款方式,返回某项投资的总期数NPER:参数1为各期利率,参数2为每期付款金额,参数3为现值pv,参数4未来值fv,参数5付款时间是在期初还是期末,前三个参数必填,后面两个选填"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.IPMT" name="IPMT" description="基于固定利率及等额分期付款方式,返回给定期数内对投资的利息偿还额函数IPMT:参数1为各期利率,参数2为用于计算其利息数额的期数,参数3为总期数,参数4现值pv,参数5未来值fv,参数6付款时间是在期初还是期末,前四个参数必填,后面两个选填"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.PPMT" name="PPMT" description="PPMT函数返回根据定期固定付款和固定利率而定的投资在已知期间内的本金偿付额:参数1为利率,参数2为期数,参数3为总期数,参数4现值pv,参数5为未来值fv,参数6付款时间是在期初还是期末,前四个参数必填,后面两个选填"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionDefineProvider class="com.fr.plugin.MIRR" name="ppmt" description="MIRR函数返回一系列定期现金流的修改后内部收益率,同时考虑投资的成本和现金再投资的收益率:参数1为现金流数组,参数2为资金支付利率,参数3为再投资收益率。"/>
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<extra-core>
<FunctionGroup class="com.fr.plugin.FinanceGroup" />
<LocaleFinder class="com.fr.plugin.FinanceFinder"/>
</extra-core>
<function-recorder class="com.fr.plugin.IRR"/>
<function-recorder class="com.fr.plugin.PMT"/>
<function-recorder class="com.fr.plugin.Rate"/>
<function-recorder class="com.fr.plugin.PPMT"/>
<function-recorder class="com.fr.plugin.IPMT"/>
<function-recorder class="com.fr.plugin.PV"/>
<function-recorder class="com.fr.plugin.FV"/>
<function-recorder class="com.fr.plugin.NPV"/>
<function-recorder class="com.fr.plugin.XIRR"/>
<function-recorder class="com.fr.plugin.NPER"/>
<function-recorder class="com.fr.plugin.MIRR"/>
</plugin>

48
plugin-finance-function/readme.md

@ -0,0 +1,48 @@
# 函数插件
该插件实现Excel中的PMT,RATE,IRR,XIRR的财务函数;
XIRR函数的功能:计算一组定期或者不定期现金流的内部收益率;
XIRR函数的语法结构:XIRR(values, dates, [guess]),
values为现金流;
dates为现金流相对应的日期;
guess为选填参数,表示预期利率,不填系统默认为10%;
XIRR使用示例:XIRR(A1:A25,B1:B25)或XIRR(A1:A25,B1:B25,0.11),所选区域支持去空,比如只有24期数据,选择A1:A34也是可以的,但为保证计算结果的准确性,必须保证中间数据是连续的;
IRR函数的功能:计算一组定期现金流的内部收益率;
IRR函数的语法结构:XIRR(values, [guess])。
values为必填参数,表示现金流;
guess为选填参数,表示预期利率,不填系统默认为10%;
IRR使用示例:XIRR(A1:A25)或XIRR(A1:A250.11),所选区域支持去空,比如只有24期数据,选择A1:A34也是可以的,但为保证计算结果的准确性,必须保证中间数据是连续的;
RATE函数的功能:计算每期年金的利率;
RATE函数的语法结构:RATE(nper, pmt, pv, [fv], [type], [guess]),
nper必填参数,为年金的付款总期数;
pmt必填参数,为每期的付款金额;
pv必填参数,为现值即一系列未来付款当前值的总和;
fv可选参数。 表示未来值,或在最后一次付款后希望得到的现金余额。 如果省略 fv,则假定其值为 0;
type可选参数,用以指定各期的付款时间是在期初还是期末,传值为数字 0-期末 或 1-期初,默认为期末;
guess可选参数,表示预期利率。如果省略 guess,则假定其值为 10%。
RATE函数使用示例:rate(24,14708.05,-315450),在相同条件下贷款的年利率为rate(24,14708.05,-315450)*12
PMT函数的功能:用于根据固定付款额和固定利率计算贷款的付款额;
PMT函数的语法结构:PMT(rate, nper, pv, [fv], [type]);
rate参数必填,表示贷款利率;
nper参数必填,表示该项贷款的付款总数,即期数;
pv参数必填,表示现值,或一系列未来付款额现在所值的总额,也叫本金;
fv可选参数。 表示未来值,或在最后一次付款后希望得到的现金余额。 如果省略 fv,则假定其值为 0;
type可选参数,用以指定各期的付款时间是在期初还是期末,传值为数字 0-期末 或 1-期初,默认为期末;
PMT使用的示例:pmt(0.078/12,24,20000,,1)或pmt(0.078/12,24,20000)

BIN
plugin-finance-function/src/.DS_Store vendored

Binary file not shown.

BIN
plugin-finance-function/src/main/.DS_Store vendored

Binary file not shown.

565
plugin-finance-function/src/main/java/com/fr/plugin/DateUtil.java

@ -0,0 +1,565 @@
package com.fr.plugin;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
*
* @{# DateUtil.java Create on 2013-4-9
*
* class desc:
*
* <p>
* Copyright: Copyright(c) 2013
* </p>
* <p>
* Company: morelap
* </p>
* @Version 1.0
* @Author <a href="mailto:morelap@morelap.com">Morelap</a>
*
*
*/
public class DateUtil {
public static final long Minute_MilliSecond = 60 * 1000;
public static final long Hour_MilliSecond = Minute_MilliSecond * 60;
/**
* milliseconds of a day
*/
public static final long Day_MilliSecond = Hour_MilliSecond * 24;
/**
* milliseconds of a week
*/
public static final long Week_MilliSecond = Day_MilliSecond * 7;
/**
* milliseconds of a month
*/
public static final long Month_MilliSecond = Week_MilliSecond * 30;
/**
* yyyyMMdd
*/
public static final String Date_Default_Formate = "yyyyMMdd";
/**
* yyyy-MM-dd HH:mm:ss 2010-05-11 17:22:26
*/
public static final String Date_Formate_All = "yyyy-MM-dd HH:mm:ss";
/**
* dd/MM/yyyy, hh:mm
*/
public static final String DATE_FORMATE_TRANSACTION = "dd/MM/yyyy, hh:mm";
/**
* MM/dd HH:mm
*/
public static final String DATE_FORMATE_DAY_HOUR_MINUTE = "MM/dd HH:mm";
/**
* HH:mm
*/
public static final String DATE_FORMATE_HOUR_MINUTE = "HH:mm";
public static final String DATE_FORMATE_HOUR_MINUTE_SECOND = "HH:mm:ss";
public static SimpleDateFormat dateFormate = new SimpleDateFormat();
/**
* 获取当前的字符串日期
*
* @param splite
* 格式的分割线如 - 则获取的日期时间格式如下
* @return 返回2013-07-19
*/
public static String getNowStringDate(String splite) {
StringBuffer format = new StringBuffer();
if (splite == null) {
format.append(Date_Default_Formate);
} else {
format.append("yyyy").append(splite).append("MM").append(splite)
.append("dd");
}
return (new SimpleDateFormat(format.toString())).format(new Date());
}
/**
* 获取当前的字符串日期时间
*
* @param splite
* 格式的分割线如 - 则获取的日期时间格式如下
* @return 返回2013-07-19 09:08:22
*/
public static String getNowStringDateTime(String splite) {
StringBuffer format = new StringBuffer();
if (splite == null) {
format.append(Date_Default_Formate);
} else {
format.append("yyyy").append(splite).append("MM").append(splite)
.append("dd").append(" HH:mm:ss");
}
return (new SimpleDateFormat(format.toString())).format(new Date());
}
/**
* 获取当前的字符串期时间
*
* @param splite
* 格式的分割线如 - 则获取的日期时间格式如下
* @return 返回09:08:22
*/
public static String getNowStringTime() {
StringBuffer format = new StringBuffer(DATE_FORMATE_HOUR_MINUTE_SECOND);
return (new SimpleDateFormat(format.toString())).format(new Date());
}
/**
* 获取昨天的日期
*
* @return Date
*/
public static Date getYesterdayDate() {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, -1);
return calendar.getTime();
}
/**
* 获取指定日期的后面的一天 即日期+1
*
* @param stringDate
* 格式为2012-02-02
* @return Date
*/
public static Date getForwardDate(String stringDate) {
int year = Integer.parseInt(stringDate.substring(0, 4));
int month = Integer.parseInt(stringDate.substring(5, 7));
int day = Integer.parseInt(stringDate.substring(8, 10));
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month - 1);
c.set(Calendar.DAY_OF_MONTH, day);
c.add(Calendar.DATE, 1);// 在此日期的基础上+1
return c.getTime();
}
/**
* 获取指定日期的后面的一天 即日期+1
*
* @param stringDate
* 格式为2012-02-02
* @return Date
*/
public static String getForwardStringDate(String stringDate, String splite) {
int year = Integer.parseInt(stringDate.substring(0, 4));
int month = Integer.parseInt(stringDate.substring(5, 7));
int day = Integer.parseInt(stringDate.substring(8, 10));
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month - 1);
c.set(Calendar.DAY_OF_MONTH, day);
c.add(Calendar.DATE, 1);// 在此日期的基础上+1
return getStringDateByDate(c.getTime(), splite);
}
/**
* 根据传进来的日期date 和格式分割线返回一个字符串的日期
*
* @param date
* 日期
* @param splite
* 日期格式的分割线 -
* @return 2013-07-19
*/
public static String getStringDateByDate(Date date, String splite) {
StringBuffer format = new StringBuffer();
if (splite == null) {
format.append(Date_Default_Formate);
} else {
format.append("yyyy").append(splite).append("MM").append(splite)
.append("dd");
}
if (date == null) {
date = new Date();
}
return (new SimpleDateFormat(format.toString())).format(date);
}
/**
* 根据传进来的日期stringdate 和格式分割线返回一个字符串的日期
*
* @param stringDate
* 日期
* @param splite
* 日期格式的分割线 -
* @return 2013-07-19
*/
public static String getStringDateByStringDate(String stringDate,
String splite) {
Date date = getDateByStringTime(stringDate);
return getStringDateByDate(date, splite);
}
/**
* 根据传进来的整数获取一个日期Date
*
* @param year
*
* @param month
*
* @param day
*
* @return Date
*/
public static Date getDateByIntegerDate(int year, int month, int day) {
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month - 1);
c.set(Calendar.DAY_OF_MONTH, day);
return c.getTime();
}
/**
* 根据传进来的字符串日期格式 获得一个date
*
* @param stringTime
* 格式如2013-02-13 中间的-可以为其他字符
* @return date
*/
public static Date getDateByStringTime(String stringTime) {
int year = Integer.parseInt(stringTime.substring(0, 4));
int month = Integer.parseInt(stringTime.substring(5, 7));
int day = Integer.parseInt(stringTime.substring(8, 10));
return getDateByIntegerDate(year, month, day);
}
/**
* 获得指定日期 在1970年到现在的天数
*
* @param date
* @return 天数
*/
public static long getDaysFrom1970(Date date) {
String stringTime = DateUtil.getStringDateByDate(date, "-");
int year = Integer.parseInt(stringTime.substring(0, 4));
int month = Integer.parseInt(stringTime.substring(5, 7));
int day = Integer.parseInt(stringTime.substring(8, 10));
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month - 1);
c.set(Calendar.DAY_OF_MONTH, day);
return (int) (c.getTimeInMillis() / 86400000);
}
/**
* 获得指定日期 在1970年到现在的天数
*
* @param
*
* @return 天数
*/
public static long getDaysFrom1970(int year, int month, int day) {
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month - 1);
c.set(Calendar.DAY_OF_MONTH, day);
return (int) (c.getTimeInMillis() / 86400000);
}
/**
* 获得指定日期 在1970年到现在的天数
*
* @param date 格式2013-03-05 中间的-可以是其他符号 或者没有符号
* @param hasSplite 代表中间是否有符号默认是有的如果为false则日期的格式为20130305
* @return 天数
*/
public static long getDaysFrom1970(String stringTime,boolean hasSplite) {
int year,month,day;
if(hasSplite){
year = Integer.parseInt(stringTime.substring(0, 4));
month = Integer.parseInt(stringTime.substring(5, 7));
day = Integer.parseInt(stringTime.substring(8, 10));
}else{
year = Integer.parseInt(stringTime.substring(0, 4));
month = Integer.parseInt(stringTime.substring(4, 6));
day = Integer.parseInt(stringTime.substring(6, 8));
}
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month - 1);
c.set(Calendar.DAY_OF_MONTH, day);
return (int) (c.getTimeInMillis() / 86400000);
}
/**
* 获得今年年初的第一天日期 如2013-01-01
*
* @param splite
* 分隔符号
* @return 2013-01-01字符串形式
*/
public static String getYearStartString(String splite) {
String sDate = getNowStringDate(splite);
int year = Integer.parseInt(sDate.substring(0, 4));
String yearStart = new StringBuffer().append(year).append(splite)
.append("01").append(splite).append("01").toString();
return yearStart;
}
/**
* 获得今年年初的第一天日期 如2013-01-01
*
* @return 2013-01-01日期格式
*/
public static Date getYearStartDate() {
String sDate = getNowStringDate("-");
int year = Integer.parseInt(sDate.substring(0, 4));
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, 0);
c.set(Calendar.DAY_OF_MONTH, 1);
return c.getTime();
}
/**
* 获得上个周末的 字符串日期 指星期日
* @param splite
* 分隔符号 -
* @return String 格式2013-06-22
*/
public static String getLastWeekStringDate(String splite) {
String stringDate=getNowStringDate("-");
int year = Integer.parseInt(stringDate.substring(0, 4));
int month = Integer.parseInt(stringDate.substring(5, 7));
int day = Integer.parseInt(stringDate.substring(8, 10));
int sundayPlus=getSundayPlus();
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month - 1);
c.set(Calendar.DAY_OF_MONTH, day);
c.add(Calendar.DATE, -sundayPlus);// 在此日期的基础上减去sundayPlus就是上个周末的日期
return getStringDateByDate(c.getTime(), splite);
}
/**
* 获得上个周末的日期date格式
*
* @return Date
*/
public static Date getLastWeekDate() {
String stringDate=getNowStringDate("-");
int year = Integer.parseInt(stringDate.substring(0, 4));
int month = Integer.parseInt(stringDate.substring(5, 7));
int day = Integer.parseInt(stringDate.substring(8, 10));
int sundayPlus=getSundayPlus();
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month - 1);
c.set(Calendar.DAY_OF_MONTH, day);
c.add(Calendar.DATE, -sundayPlus);// 在此日期的基础上减去sundayPlus就是上个周末的日期
return c.getTime();
}
/**
* 获得上个月末的 字符串日期
* @return String
*/
public static String getLastMonthStringDate(String splite) {
String stringDate=getNowStringDate("-");
int year = Integer.parseInt(stringDate.substring(0, 4));
int month = Integer.parseInt(stringDate.substring(5, 7));
int day = Integer.parseInt(stringDate.substring(8, 10));
int monthPlus=getMonthPlus();
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month - 1);
c.set(Calendar.DAY_OF_MONTH, day);
c.add(Calendar.DATE, -monthPlus);// 在此日期的基础上减去sundayPlus就是上个周末的日期
return getStringDateByDate(c.getTime(), splite);
}
/**
* 获得上个月末的日期date格式
*
* @return Date
*/
public static Date getLastMonthDate() {
String stringDate=getNowStringDate("-");
int year = Integer.parseInt(stringDate.substring(0, 4));
int month = Integer.parseInt(stringDate.substring(5, 7));
int day = Integer.parseInt(stringDate.substring(8, 10));
int monthPlus=getMonthPlus();
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month - 1);
c.set(Calendar.DAY_OF_MONTH, day);
c.add(Calendar.DATE, -monthPlus);// 在此日期的基础上减去sundayPlus就是上个周末的日期
return c.getTime();
}
/**
* 获得上个季度末的 字符串日期
* @return String 2012-03-30
*/
public static String getLastQuarterStringDate(String splite) {
String stringDate=getNowStringDate("-");
int year = Integer.parseInt(stringDate.substring(0, 4));
int month = Integer.parseInt(stringDate.substring(5, 7));
switch (month) {
case 1:
case 2:
case 3:
month=12;
year--;
break;
case 4:
case 5:
case 6:
month=3;
break;
case 7:
case 8:
case 9:
month=6;
break;
case 10:
case 11:
case 12:
month=9;
break;
default:
break;
}
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month);//这里月份本来是要-1的,所以这里就相当于月份month+1,
c.set(Calendar.DAY_OF_MONTH, 1);//此时的日期刚好为month+1月份的一号
c.add(Calendar.DATE, -1);// 在1号的基础上减去一天,就是month月末的日期
return getStringDateByDate(c.getTime(), splite);
}
/**
* 获得上个季度末的日期date格式
* @return Date
*/
public static Date getLastQuarterDate() {
String stringDate=getNowStringDate("-");
int year = Integer.parseInt(stringDate.substring(0, 4));
int month = Integer.parseInt(stringDate.substring(5, 7));
switch (month) {
case 1:
case 2:
case 3:
month=12;
year--;
break;
case 4:
case 5:
case 6:
month=3;
break;
case 7:
case 8:
case 9:
month=6;
break;
case 10:
case 11:
case 12:
month=9;
break;
default:
break;
}
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month);//这里月份本来是要-1的,所以这里就相当于月份month+1,
c.set(Calendar.DAY_OF_MONTH, 1);//此时的日期刚好为month+1月份的一号
c.add(Calendar.DATE, -1);// 在1号的基础上减去一天,就是month月末的日期
return c.getTime();
}
/**
* 获得指定月份的月末日期
* @param month
* @return String
*/
public static String getMonthEndStringDateByMonth(int month,String splite){
String stringDate=getNowStringDate("-");
int year = Integer.parseInt(stringDate.substring(0, 4));
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month);//这里月份本来是要-1的,所以这里就相当于月份month+1,
c.set(Calendar.DAY_OF_MONTH, 1);//此时的日期刚好为month+1月份的一号
c.add(Calendar.DATE, -1);// 在1号的基础上减去一天,就是month月末的日期
return getStringDateByDate(c.getTime(), splite);
}
/**
* 获得当前日期与上周日相差的天数 按照外国的理解星期日是第一天星期一是第二天. 中国星期一是第一天.
*
* @return int今天和上周日的相差日期
*/
public static int getSundayPlus() {
Calendar c = Calendar.getInstance();
// 获得今天是一周的第几天,星期日是第一天,星期二是第二天......
int dayOfWeek = c.get(Calendar.DAY_OF_WEEK) - 1; // 因为按中国礼拜一,作为第一天所以这里减1
if(dayOfWeek==0){
dayOfWeek=7;
}
return dayOfWeek;
}
/**
* 获得当前日期与上个月末日期的相差天数
*
* @return int 今天和上月末的相差日期
*/
public static int getMonthPlus() {
Calendar c = Calendar.getInstance();
// 获得今天是一周的第几天,星期日是第一天,星期二是第二天......
int dayOfMonth = c.get(Calendar.DAY_OF_MONTH);
return dayOfMonth;
}
/**
* 获得两个时间相差的时间间隔以分钟来计算
* @param time01 格式为2012-02-02 08:08:20
* @param time02 格式为2012-02-02 08:08:20
* @return 相差的分钟数
*/
public static long getTwoTimeInterval(String time01,String time02){
long t01=stringTimeToMilliseconds(time01);
long t02=stringTimeToMilliseconds(time02);
return Math.abs((t01-t02)/60000);
}
/**
* 把一个字符串日期 转换成毫秒数
* @param time 格式为2012-02-02 08:08:20
* @return 毫秒数
*/
public static long stringTimeToMilliseconds(String time){
int year = Integer.parseInt(time.substring(0, 4));
int month = Integer.parseInt(time.substring(5, 7));
int day = Integer.parseInt(time.substring(8, 10));
int hour= Integer.parseInt(time.substring(11, 13));
int minus= Integer.parseInt(time.substring(14, 16));
int second= Integer.parseInt(time.substring(17, 19));
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month - 1);
c.set(Calendar.DAY_OF_MONTH, day);
c.add(Calendar.HOUR_OF_DAY, hour);
c.add(Calendar.MINUTE, minus);
c.add(Calendar.SECOND, second);
return c.getTimeInMillis();
}
// java.util.Date 是 java.sql.Date 的父类
// java.sql.Date转为java.util.Date
// java.sql.Date date=new java.sql.Date();
// java.util.Date d=new java.util.Date (date.getTime());
//
//
// java.util.Date转为java.sql.Date
// java.util.Date utilDate=new Date();
// java.sql.Date sqlDate=new java.sql.Date(utilDate.getTime());
}

60
plugin-finance-function/src/main/java/com/fr/plugin/FV.java

@ -0,0 +1,60 @@
package com.fr.plugin;
import com.fr.general.GeneralUtils;
import com.fr.intelli.record.Focus;
import com.fr.intelli.record.Original;
import com.fr.plugin.context.PluginContexts;
import com.fr.record.analyzer.EnableMetrics;
import com.fr.script.AbstractFunction;
import com.fr.stable.StringUtils;
import com.fr.stable.exception.FormulaException;
import com.fr.stable.fun.Authorize;
import com.fr.third.v2.org.apache.poi.ss.formula.functions.FinanceLib;
import java.math.BigDecimal;
@EnableMetrics
@Authorize(callSignKey = FinanceFunctionConstants.PLUGIN_ID)
public class FV extends AbstractFunction {
@Override
@Focus(id = "com.fr.plugin.function.finance", text = "Plugin-Test_Function_Finance", source = Original.PLUGIN)
public Object run(Object[] objects) throws FormulaException {
if (PluginContexts.currentContext().isAvailable()) {
return cal(objects);
} else {
return "插件未激活,请购买使用";
}
}
private Object cal(Object[] objects) {
//年利率
double rate = trans(objects[0]).doubleValue();
//贷款期数
double nper = trans(objects[1]).doubleValue();
//每期的付款金额
double pmt= trans(objects[2]).doubleValue();
//pv 可选
double pv = 0D;
if(objects.length == 4) {
pv = trans(objects[3]).doubleValue();
}
//type 可选
boolean type=false;
if(objects.length == 5) {
pv = trans(objects[3]).doubleValue();
type = trans(objects[4]).doubleValue()==1;
}
return FinanceLib.fv(rate,nper,pmt,pv,type);
}
private static BigDecimal trans(Object ele){
if (ele == null|| StringUtils.isBlank(ele.toString())) {
return new BigDecimal("0");
}
try{
String val = GeneralUtils.objectToString(ele);
return new BigDecimal(val.trim());
}catch(Exception e){
throw new RuntimeException(e);
}
}
}

10
plugin-finance-function/src/main/java/com/fr/plugin/FinanceFinder.java

@ -0,0 +1,10 @@
package com.fr.plugin;
import com.fr.stable.fun.impl.AbstractLocaleFinder;
public class FinanceFinder extends AbstractLocaleFinder {
@Override
public String find() {
return "com/fr/plugin/demo";
}
}

6
plugin-finance-function/src/main/java/com/fr/plugin/FinanceFunctionConstants.java

@ -0,0 +1,6 @@
package com.fr.plugin;
public class FinanceFunctionConstants {
public static final String PLUGIN_ID = "com.fr.plugin.function.finance";
}

29
plugin-finance-function/src/main/java/com/fr/plugin/FinanceGroup.java

@ -0,0 +1,29 @@
package com.fr.plugin;
import com.fr.stable.fun.impl.AbstractFunctionDefContainer;
import com.fr.stable.script.FunctionDef;
public class FinanceGroup extends AbstractFunctionDefContainer {
@Override
public FunctionDef[] getFunctionDefs() {
return new FunctionDef[]{
new FunctionDef("IPMT","基于固定利率及等额分期付款方式,返回给定期数内对投资的利息偿还额函数IPMT:参数1为每期期利率,参数2为用于计算其利息数额的期数,参数3为总期数,参数4现值pv,参数5未来值fv,参数6付款时间是在期初还是期末,前四个参数必填,后面两个选填。",IPMT.class.getName()),
new FunctionDef("PPMT","PPMT函数返回根据定期固定付款和固定利率而定的投资在已知期间内的本金偿付额:参数1为每期利率,参数2为期数,参数3为总期数,参数4现值pv,参数5为未来值fv,参数6付款时间是在期初还是期末,前四个参数必填,后面两个选填。",PPMT.class.getName()),
new FunctionDef("PMT","PMT函数根据固定付款额和固定利率计算贷款的付款额:参数1为每期利率,参数2为贷款总期数,参数3现值pv即本金,参数4为未来值fv,参数5为付款时间是在期初还是期末,前三个参数必填,后面两个选填。",PMT.class.getName()),
new FunctionDef("PV","投资的现值PV:参数1为每期利率,参数2为总期数,参数3为每期付款金额,参数4未来值fv,参数5付款时间是在期初还是期末,前三个参数必填,后面两个选填。",PV.class.getName()),
new FunctionDef("FV","计算投资价值的函数FV:参数1为利率,参数2为总期数,参数3为每期付款金额,参数4现值pv,参数5每期付款时间是在期初还是期末,前三个参数必填,后面两个选填。",FV.class.getName()),
new FunctionDef("NPV","使用贴现率和一系列未来支出(负值)和收益(正值)来计算一项投资的净现值NPV:参数1为利率,可变参数-现金流,按正确的顺序输入支出值和收益值。",NPV.class.getName()),
new FunctionDef("NPER","基于固定利率及等额分期付款方式,返回某项投资的总期数NPER:参数1为各期利率,参数2为每期付款金额,参数3为现值pv,参数4未来值fv,参数5付款时间是在期初还是期末,前三个参数必填,后面两个选填。",NPER.class.getName()),
new FunctionDef("IRR","IRR函数返回由值中的数字表示的一系列现金流的内部收益率:参数1为现金流数组,参数2为估计值,参数2为选填,如果省略guess,则假定它为0.1。",IRR.class.getName()),
new FunctionDef("XIRR","XIRR函数返回一组不一定定期发生的现金流的内部收益率:参数1为现金流数组,参数2为对应还款日期列表,参数3估计值为选填。",XIRR.class.getName()),
new FunctionDef("Rate","RATE函数返回年金每期的利率:参数1为贷款总期数,参数2为每期付款金额,参数3为付款金额的总和,参数4为未来值fv,参数5为type付款时间是在期初还是期末,参数6为预期利率,省略的话默认为0.1,前三个参数必填,后三个选填。",Rate.class.getName()),
new FunctionDef("MIRR","MIRR函数返回一系列定期现金流的修改后内部收益率,同时考虑投资的成本和现金再投资的收益率:参数1为现金流数组,参数2为资金支付利率,参数3为再投资收益率。",MIRR.class.getName())
};
}
@Override
public String getGroupName() {
return "财务函数";
}
}

66
plugin-finance-function/src/main/java/com/fr/plugin/IPMT.java

@ -0,0 +1,66 @@
package com.fr.plugin;
import com.fr.general.GeneralUtils;
import com.fr.intelli.record.Focus;
import com.fr.intelli.record.Original;
import com.fr.plugin.context.PluginContexts;
import com.fr.record.analyzer.EnableMetrics;
import com.fr.script.AbstractFunction;
import com.fr.stable.StringUtils;
import com.fr.stable.exception.FormulaException;
import com.fr.stable.fun.Authorize;
import com.fr.third.v2.org.apache.poi.ss.formula.functions.Finance;
import java.math.BigDecimal;
@EnableMetrics
@Authorize(callSignKey = FinanceFunctionConstants.PLUGIN_ID)
public class IPMT extends AbstractFunction {
@Override
@Focus(id = "com.fr.plugin.function.finance", text = "Plugin-Test_Function_Finance", source = Original.PLUGIN)
public Object run(Object[] objects) throws FormulaException {
if (PluginContexts.currentContext().isAvailable()) {
return cal(objects);
} else {
return "插件未激活,请购买使用";
}
}
private Object cal(Object[] objects) {
// 各期利率 必需
double rate = trans(objects[0]).doubleValue();
// 指定期数 per 必需
int per = trans(objects[1]).intValue();
//年金的付款总期数 必需
int nper = trans(objects[2]).intValue();
//pv 必需 现值即一系列未来付款当前值的总和
double pv = trans(objects[3]).doubleValue();
if (objects.length == 4) {
return Finance.ipmt(rate,per,nper,pv);
}else if (objects.length == 5) {
//未来值
double fv = trans(objects[4]).doubleValue();
return Finance.ipmt(rate,per,nper,pv,fv);
}else if (objects.length == 6) {
double fv = trans(objects[4]).doubleValue();
int type= trans(objects[5]).intValue();
return Finance.ipmt(rate,per,nper,pv,fv,type);
}else {
throw new RuntimeException("输入参数有误");
}
}
private static BigDecimal trans(Object ele){
if (ele == null|| StringUtils.isBlank(ele.toString())) {
return new BigDecimal("0");
}
try{
String val = GeneralUtils.objectToString(ele);
return new BigDecimal(val.trim());
}catch(Exception e){
throw new RuntimeException(e);
}
}
}

196
plugin-finance-function/src/main/java/com/fr/plugin/IRR.java

@ -0,0 +1,196 @@
package com.fr.plugin; /**
* @file: PACKAGE_NAME.IRR
* @desc:
* @date:2020/7/7 16:57
* @author:yanghui
**/
import com.fr.general.FArray;
import com.fr.general.GeneralUtils;
import com.fr.intelli.record.Focus;
import com.fr.intelli.record.Original;
import com.fr.plugin.context.PluginContexts;
import com.fr.record.analyzer.EnableMetrics;
import com.fr.script.AbstractFunction;
import com.fr.stable.StringUtils;
import com.fr.stable.fun.Authorize;
import java.math.BigDecimal;
@EnableMetrics
@Authorize(callSignKey = FinanceFunctionConstants.PLUGIN_ID)
public class IRR extends AbstractFunction {
private static final long serialVersionUID = 7634415917398642321L;
private static final String ERROR_VALUE = "#NUM!";
@Override
@Focus(id = "com.fr.plugin.function.finance", text = "Plugin-Test_Function_Finance", source = Original.PLUGIN)
public Object run(Object[] args) {
if (PluginContexts.currentContext().isAvailable()) {
return cal(args);
} else {
return "插件未激活,请购买使用";
}
}
private Object cal(Object[] args) {
try{
if(1 == args.length){
return run( transArr( (FArray) args[0] ) );
}else if(2 == args.length){
return run( transArr( (FArray) args[0] ), trans( args[1] ) );
}else if(3==args.length){
return "参数个数不合格!";
}
else{
FArray<BigDecimal> cashflow = new FArray<BigDecimal>();
BigDecimal guess = new BigDecimal(0.1d);
for (int i = 0; i < args.length; i++) {
if(args[i] == null|| StringUtils.isBlank(args[i].toString())){
continue;
}
BigDecimal var = new BigDecimal(GeneralUtils.objectToString(args[i]).trim());
if ((var.compareTo(BigDecimal.ONE) <1) && (var.compareTo(BigDecimal.ZERO)>-1)) {
guess = var;
}else {
cashflow.add(var);
}
}
return run(cashflow,guess);
}
}catch(Exception e){
System.out.println(e);
}
return ERROR_VALUE;
}
/**
* 将其他类型的数字转换为大数保证精度
* @param ele
* @return
*/
private static BigDecimal trans(Object ele){
try{
String val = GeneralUtils.objectToString(ele);
return new BigDecimal(val.trim());
}catch(Exception e){
throw new RuntimeException(e);
}
}
/**
* 将数组转换为大数数组
* @param in
* @return
*/
private static FArray<BigDecimal> transArr(FArray in){
FArray<BigDecimal> rt = new FArray<BigDecimal>();
for(int i=0;i<in.length();i++){
Object ele = in.elementAt(i);
if(ele == null|| StringUtils.isBlank(ele.toString())){
continue;
}
rt.add(trans(ele));
}
return rt;
}
private static BigDecimal run(FArray<BigDecimal> cashflow){
return run( cashflow, new BigDecimal(0.1d) );
}
private static BigDecimal run(FArray<BigDecimal> cashflow, BigDecimal guess){
BigDecimal maxrate = initRateMax(cashflow,guess);
BigDecimal minrate = initRateMin(cashflow,guess);
for( int i=0; i<Init_Max_Loop; i++ ){
BigDecimal testrate = minrate.add(maxrate).divide( new BigDecimal(2d) );
BigDecimal npv = NPV( cashflow, testrate );
if( npv.abs().compareTo(Accuracy) == LESS ){
guess = testrate;
break;
}else if( npv.compareTo(ZERO) == LESS ){
minrate = testrate;
}else{
maxrate = testrate;
}
}
//保留16位小数(足够精度)
return guess.setScale(16,BigDecimal.ROUND_HALF_UP);
}
//最小精度
private static final BigDecimal Accuracy = new BigDecimal(0.00000001d);
//最大循环次数,excel用的是20次,不过精度只到小数点后两位,而且不一定一定能算出值,为了尽可能保证算出结果,我增加到100次,
private static final int Init_Max_Loop = 100;
private static final BigDecimal ZERO = new BigDecimal(0);
private static final BigDecimal ONE = new BigDecimal(1);
private static final BigDecimal Z005 = new BigDecimal(0.005d);
private static final BigDecimal Z2 = new BigDecimal(0.2d);
private static final int GREATER = 1;
private static final int LESS = -1;
/**
* 生成一个使NPV为负数的R作为内部收益率下限值
* @param cashflow
* @param guess
* @return
*/
private static BigDecimal initRateMin(FArray<BigDecimal> cashflow, BigDecimal guess){
for( int i=0; i<Init_Max_Loop; i++ ){
BigDecimal npv = NPV( cashflow, guess );
if( npv.compareTo(ZERO) == LESS ){
return guess;
}
BigDecimal step = guess.abs().multiply( Z2 );
guess = guess.add( step.compareTo( Z005 ) == LESS ? Z005 : step );
}
return guess;
}
/**
* 生成一个使NPV为正数的R作为内部收益率的上限制
* @param cashflow
* @param guess
* @return
*/
private static BigDecimal initRateMax(FArray<BigDecimal> cashflow, BigDecimal guess){
for( int i=0; i<Init_Max_Loop; i++ ){
BigDecimal npv = NPV( cashflow, guess );
if( npv.compareTo(ZERO) == GREATER ){
return guess;
}
BigDecimal step = guess.abs().multiply( Z2 );
guess = guess.subtract( step.compareTo( Z005 ) == LESS ? Z005 : step );
}
return guess;
}
/**
* 算NPV
* @param cashflow
* @param rate
* @return
*/
private static BigDecimal NPV(FArray<BigDecimal> cashflow, BigDecimal rate){
BigDecimal npv = ZERO;
BigDecimal rpowj = ONE;//(1+r)^0
BigDecimal radd1 = rate.add(ONE);//1+r
for( int j=0; j<cashflow.length(); j++ ){
BigDecimal valuej = cashflow.elementAt(j);
npv = npv.add( valuej.divide( rpowj, 10, BigDecimal.ROUND_HALF_DOWN ) );// vj / (1+r)^j
rpowj = rpowj.multiply(radd1); // (1+r)^j
//npv += cashflow.elementAt(j) / Math.pow( 1+rate, j );
}
return npv;
}
}

112
plugin-finance-function/src/main/java/com/fr/plugin/MIRR.java

@ -0,0 +1,112 @@
package com.fr.plugin;
import com.fr.general.FArray;
import com.fr.general.GeneralUtils;
import com.fr.intelli.record.Focus;
import com.fr.intelli.record.Original;
import com.fr.plugin.context.PluginContexts;
import com.fr.record.analyzer.EnableMetrics;
import com.fr.script.AbstractFunction;
import com.fr.stable.StringUtils;
import com.fr.stable.exception.FormulaException;
import com.fr.stable.fun.Authorize;
import java.math.BigDecimal;
@EnableMetrics
@Authorize(callSignKey = FinanceFunctionConstants.PLUGIN_ID)
public class MIRR extends AbstractFunction {
@Override
@Focus(id = "com.fr.plugin.function.finance", text = "Plugin-Test_Function_Finance", source = Original.PLUGIN)
public Object run(Object[] objects) throws FormulaException {
if (PluginContexts.currentContext().isAvailable()) {
return cal(objects);
} else {
return "插件未激活,请购买使用";
}
}
private Object cal(Object[] objects) {
//资金支付利率
double financeRate;
double reinvestRate;
//再投资收益率
if (objects.length < 3) {
throw new RuntimeException("输入参数个数有误");
} else if (objects.length == 3) {
FArray in = (FArray) objects[0];
//现金流
double[] cashIn = new double[in.length()];
for(int i=0;i<in.length();i++){
Object ele = in.elementAt(i);
if(ele == null|| StringUtils.isBlank(ele.toString())){
continue;
}
cashIn[i] = trans(ele).doubleValue();
}
financeRate = trans(objects[2]).doubleValue();
reinvestRate = trans(objects[1]).doubleValue();
return mirr(cashIn, financeRate, reinvestRate);
}else {
double[] cashIn = new double[objects.length - 2];
for (int i = 0; i < objects.length - 2; i++) {
if (objects[i] == null || StringUtils.isBlank(objects[i].toString())) {
continue;
}
cashIn[i] = trans(objects[i]).doubleValue();
}
financeRate = trans(objects[objects.length - 1]).doubleValue();
reinvestRate = trans(objects[objects.length - 2]).doubleValue();
return mirr(cashIn, financeRate, reinvestRate);
}
}
private static BigDecimal trans(Object ele){
if (ele == null|| StringUtils.isBlank(ele.toString())) {
return new BigDecimal("0");
}
try{
String val = GeneralUtils.objectToString(ele);
return new BigDecimal(val.trim());
}catch(Exception e){
throw new RuntimeException(e);
}
}
private double mirr(double[] in, double financeRate, double reinvestRate) {
double value = 0.0D;
int numOfYears = in.length - 1;
double pv = 0.0D;
double fv = 0.0D;
int indexN = 0;
double[] var13 = in;
int var14 = in.length;
double anIn;
int var15;
for(var15 = 0; var15 < var14; ++var15) {
anIn = var13[var15];
if (anIn < 0.0D) {
pv += anIn / Math.pow(1.0D + financeRate + reinvestRate, (double)(indexN++));
}
}
var13 = in;
var14 = in.length;
for(var15 = 0; var15 < var14; ++var15) {
anIn = var13[var15];
if (anIn > 0.0D) {
fv += anIn * Math.pow(1.0D + financeRate, (double)(numOfYears - indexN++));
}
}
if (fv != 0.0D && pv != 0.0D) {
value = Math.pow(-fv / pv, 1.0D / (double)numOfYears) - 1.0D;
}
return value;
}
}

62
plugin-finance-function/src/main/java/com/fr/plugin/NPER.java

@ -0,0 +1,62 @@
package com.fr.plugin;
import com.fr.general.GeneralUtils;
import com.fr.intelli.record.Focus;
import com.fr.intelli.record.Original;
import com.fr.plugin.context.PluginContexts;
import com.fr.record.analyzer.EnableMetrics;
import com.fr.script.AbstractFunction;
import com.fr.stable.StringUtils;
import com.fr.stable.exception.FormulaException;
import com.fr.stable.fun.Authorize;
import com.fr.third.v2.org.apache.poi.ss.formula.functions.FinanceLib;
import java.math.BigDecimal;
@EnableMetrics
@Authorize(callSignKey = FinanceFunctionConstants.PLUGIN_ID)
public class NPER extends AbstractFunction {
@Override
@Focus(id = "com.fr.plugin.function.finance", text = "Plugin-Test_Function_Finance", source = Original.PLUGIN)
public Object run(Object[] objects) throws FormulaException {
if (PluginContexts.currentContext().isAvailable()) {
return cal(objects);
} else {
return "插件未激活,请购买使用";
}
}
private Object cal(Object[] objects) {
//某一期间的贴现率
double rate = trans(objects[0]).doubleValue();
//每期的付款金额
double pmt= trans(objects[1]).doubleValue();
//pv 可选
double pv = trans(objects[2]).doubleValue();
//fv 可选
double fv = 0D;
if(objects.length == 4) {
fv = trans(objects[3]).doubleValue();
}
//type 可选
boolean type=false;
if(objects.length == 5) {
fv = trans(objects[3]).doubleValue();
type = trans(objects[4]).doubleValue()==1;
}
return FinanceLib.nper(rate,pmt,pv,fv,type);
}
private static BigDecimal trans(Object ele){
if (ele == null|| StringUtils.isBlank(ele.toString())) {
return new BigDecimal("0");
}
try{
String val = GeneralUtils.objectToString(ele);
return new BigDecimal(val.trim());
}catch(Exception e){
throw new RuntimeException(e);
}
}
}

52
plugin-finance-function/src/main/java/com/fr/plugin/NPV.java

@ -0,0 +1,52 @@
package com.fr.plugin;
import com.fr.general.GeneralUtils;
import com.fr.intelli.record.Focus;
import com.fr.intelli.record.Original;
import com.fr.plugin.context.PluginContexts;
import com.fr.record.analyzer.EnableMetrics;
import com.fr.script.AbstractFunction;
import com.fr.stable.StringUtils;
import com.fr.stable.exception.FormulaException;
import com.fr.stable.fun.Authorize;
import com.fr.third.v2.org.apache.poi.ss.formula.functions.FinanceLib;
import java.math.BigDecimal;
@EnableMetrics
@Authorize(callSignKey = FinanceFunctionConstants.PLUGIN_ID)
public class NPV extends AbstractFunction {
@Override
@Focus(id = "com.fr.plugin.function.finance", text = "Plugin-Test_Function_Finance", source = Original.PLUGIN)
public Object run(Object[] objects) throws FormulaException {
if (PluginContexts.currentContext().isAvailable()) {
return cal(objects);
} else {
return "插件未激活,请购买使用";
}
}
private Object cal(Object[] objects){
//某一期间的贴现率
double rate = trans(objects[0]).doubleValue();
double[] doubles = new double[objects.length];
for (int i = 1; i <objects.length ; i++) {
doubles[i-1]=(trans(objects[i]).doubleValue());
}
return FinanceLib.npv(rate,doubles);
}
private static BigDecimal trans(Object ele){
if (ele == null|| StringUtils.isBlank(ele.toString())) {
return new BigDecimal("0");
}
try{
String val = GeneralUtils.objectToString(ele);
return new BigDecimal(val.trim());
}catch(Exception e){
throw new RuntimeException(e);
}
}
}

82
plugin-finance-function/src/main/java/com/fr/plugin/PMT.java

@ -0,0 +1,82 @@
package com.fr.plugin;
import com.fr.general.GeneralUtils;
import com.fr.intelli.record.Focus;
import com.fr.intelli.record.Original;
import com.fr.plugin.context.PluginContexts;
import com.fr.record.analyzer.EnableMetrics;
import com.fr.script.AbstractFunction;
import com.fr.stable.StringUtils;
import com.fr.stable.exception.FormulaException;
import com.fr.stable.fun.Authorize;
import java.math.BigDecimal;
/**
* @file: PACKAGE_NAME.PMT
* @desc:
* @date:2020/7/7 17:06
* @author:yanghui
**/
@EnableMetrics
@Authorize(callSignKey = FinanceFunctionConstants.PLUGIN_ID)
public class PMT extends AbstractFunction {
@Override
@Focus(id = "com.fr.plugin.function.finance", text = "Plugin-Test_Function_Finance", source = Original.PLUGIN)
public Object run(Object[] objects) throws FormulaException {
if (PluginContexts.currentContext().isAvailable()) {
return cal(objects);
} else {
return "插件未激活,请购买使用";
}
}
private Object cal(Object[] objects) {
//年利率
double rate = trans(objects[0]).doubleValue();
//贷款期数
double nper = trans(objects[1]).doubleValue();
//贷款金额
double pv= trans(objects[2]).doubleValue();
if (objects.length == 3) {
return calculatePMT(rate, nper, pv, 0, 0);
}
else if (objects.length == 4) {
//fv为未来值(余值),或在最后一次付款后希望得到的现金余额,如果省略fv,则假设其值为零,也就是一笔贷款的未来值为零
double fv = trans(objects[3]).doubleValue();
return calculatePMT(rate, nper, pv, fv, 0);
}else if(objects.length == 5){
//fv为未来值(余值),或在最后一次付款后希望得到的现金余额,如果省略fv,则假设其值为零,也就是一笔贷款的未来值为零
double fv = trans(objects[3]).doubleValue();
//Type数字0或1,用以指定各期的付款时间是在期初还是期末。1代表期初(先付:每期的第一天付),不输入或输入0代表期末(后付:每期的最后一天付)
int type=Integer.valueOf(objects[4].toString());
return calculatePMT(rate,nper,pv,fv,type);
}else {
throw new RuntimeException("输入参数个数有误");
}
}
private static BigDecimal trans(Object ele){
if (ele == null|| StringUtils.isBlank(ele.toString())) {
return new BigDecimal("0");
}
try{
String val = GeneralUtils.objectToString(ele);
return new BigDecimal(val.trim());
}catch(Exception e){
throw new RuntimeException(e);
}
}
/**
*
* @param rate
* @param nper
* @param pv
* @return
*/
public static double calculatePMT(double rate, double nper, double pv,double fv, int type) {
return -rate * (fv + pv * Math.pow(1 + rate, nper)) / ((Math.pow(1 + rate, nper) - 1) * (1 + rate * type));
}
}

68
plugin-finance-function/src/main/java/com/fr/plugin/PPMT.java

@ -0,0 +1,68 @@
package com.fr.plugin;
import com.fr.general.GeneralUtils;
import com.fr.intelli.record.Focus;
import com.fr.intelli.record.Original;
import com.fr.plugin.context.PluginContexts;
import com.fr.record.analyzer.EnableMetrics;
import com.fr.script.AbstractFunction;
import com.fr.stable.StringUtils;
import com.fr.stable.exception.FormulaException;
import com.fr.stable.fun.Authorize;
import com.fr.third.v2.org.apache.poi.ss.formula.functions.Finance;
import java.math.BigDecimal;
@EnableMetrics
@Authorize(callSignKey = FinanceFunctionConstants.PLUGIN_ID)
public class PPMT extends AbstractFunction {
@Override
@Focus(id = "com.fr.plugin.function.finance", text = "Plugin-Test_Function_Finance", source = Original.PLUGIN)
public Object run(Object[] objects) throws FormulaException {
if (PluginContexts.currentContext().isAvailable()) {
return cal(objects);
} else {
return "插件未激活,请购买使用";
}
}
private Object cal(Object[] objects) {
// 各期利率 必需
double rate = trans(objects[0]).doubleValue();
// 指定期数 per 必需
int per = trans(objects[1]).intValue();
//年金的付款总期数 必需
int nper = trans(objects[2]).intValue();
//pv 必需 现值即一系列未来付款当前值的总和
double pv = trans(objects[3]).doubleValue();
if (objects.length == 4) {
return Finance.ppmt(rate,per,nper,pv);
}else if (objects.length == 5) {
//未来值
double fv = trans(objects[4]).doubleValue();
return Finance.ppmt(rate,per,nper,pv,fv);
}else if (objects.length == 6) {
double fv = trans(objects[4]).doubleValue();
int type= trans(objects[5]).intValue();
if (type == 1 && per == 1) {
return Finance.pmt(rate, nper, pv, fv, type);
}
return Finance.ppmt(rate,per,nper,pv,fv,type);
}else {
throw new RuntimeException("输入参数有误");
}
}
private static BigDecimal trans(Object ele){
if (ele == null|| StringUtils.isBlank(ele.toString())) {
return new BigDecimal("0");
}
try{
String val = GeneralUtils.objectToString(ele);
return new BigDecimal(val.trim());
}catch(Exception e){
throw new RuntimeException(e);
}
}
}

63
plugin-finance-function/src/main/java/com/fr/plugin/PV.java

@ -0,0 +1,63 @@
package com.fr.plugin;
import com.fr.general.GeneralUtils;
import com.fr.intelli.record.Focus;
import com.fr.intelli.record.Original;
import com.fr.plugin.context.PluginContexts;
import com.fr.record.analyzer.EnableMetrics;
import com.fr.script.AbstractFunction;
import com.fr.stable.StringUtils;
import com.fr.stable.exception.FormulaException;
import com.fr.stable.fun.Authorize;
import com.fr.third.v2.org.apache.poi.ss.formula.functions.FinanceLib;
import java.math.BigDecimal;
@EnableMetrics
@Authorize(callSignKey = FinanceFunctionConstants.PLUGIN_ID)
public class PV extends AbstractFunction {
@Override
@Focus(id = "com.fr.plugin.function.finance", text = "Plugin-Test_Function_Finance", source = Original.PLUGIN)
public Object run(Object[] objects) throws FormulaException {
if (PluginContexts.currentContext().isAvailable()) {
return cal(objects);
} else {
return "插件未激活,请购买使用";
}
}
private Object cal(Object[] objects) {
//年利率
double rate = trans(objects[0]).doubleValue();
//贷款期数
double nper = trans(objects[1]).doubleValue();
//每期的付款金额
double pmt= trans(objects[2]).doubleValue();
//fv 可选
double fv = 0D;
if(objects.length == 4) {
fv = trans(objects[3]).doubleValue();
}
//type 可选
boolean type=false;
if(objects.length == 5) {
fv = trans(objects[3]).doubleValue();
type = trans(objects[4]).doubleValue()==1;
}
return FinanceLib.pv(rate,nper,pmt,fv,type);
}
private static BigDecimal trans(Object ele){
if (ele == null|| StringUtils.isBlank(ele.toString())) {
return new BigDecimal("0");
}
try{
String val = GeneralUtils.objectToString(ele);
return new BigDecimal(val.trim());
}catch(Exception e){
throw new RuntimeException(e);
}
}
}

130
plugin-finance-function/src/main/java/com/fr/plugin/Rate.java

@ -0,0 +1,130 @@
package com.fr.plugin;
import com.fr.general.GeneralUtils;
import com.fr.intelli.record.Focus;
import com.fr.intelli.record.Original;
import com.fr.plugin.context.PluginContexts;
import com.fr.record.analyzer.EnableMetrics;
import com.fr.script.AbstractFunction;
import com.fr.stable.StringUtils;
import com.fr.stable.exception.FormulaException;
import com.fr.stable.fun.Authorize;
import java.math.BigDecimal;
/**
* @file: PACKAGE_NAME.Rate
* @desc:
* @date:2020/7/7 17:13
* @author:yanghui
**/
@EnableMetrics
@Authorize(callSignKey = FinanceFunctionConstants.PLUGIN_ID)
public class Rate extends AbstractFunction {
@Override
@Focus(id = "com.fr.plugin.function.finance", text = "Plugin-Test_Function_Finance", source = Original.PLUGIN)
public Object run(Object[] objects) throws FormulaException {
if (PluginContexts.currentContext().isAvailable()) {
return cal(objects);
} else {
return "插件未激活,请购买使用";
}
}
private Object cal(Object[] objects) {
//总期数
int nper = trans(objects[0]).intValue();
//每期付款金额
double pmt= trans(objects[1]).doubleValue();
//付款总金额
double pv= trans(objects[2]).doubleValue();
double fv = 0D;
double type = 0D;
double guess = 0.1D;
if(objects.length==3){
return simpleCalculateRate(nper,pmt,pv);
} else if (objects.length == 4) {
fv = trans(objects[3]).doubleValue();
return calculateRate(nper,pmt,pv,fv,type,guess);
} else if (objects.length == 5) {
fv = trans(objects[3]).doubleValue();
type=trans(objects[4]).doubleValue();
return calculateRate(nper,pmt,pv,fv,type,guess);
} else if (objects.length == 6) {
fv = trans(objects[3]).doubleValue();
type=trans(objects[4]).doubleValue();
guess=trans(objects[5]).doubleValue();
return calculateRate(nper,pmt,pv,fv,type,guess);
}else {
throw new RuntimeException("输入参数格式有误");
}
}
private static BigDecimal trans(Object ele){
if (ele == null|| StringUtils.isBlank(ele.toString())) {
return new BigDecimal("0");
}
try{
String val = GeneralUtils.objectToString(ele);
return new BigDecimal(val.trim());
}catch(Exception e){
throw new RuntimeException(e);
}
}
public double calculateRate(int nper, double pmt, double pv, double fv, double type, double guess) {
//FROM MS http://office.microsoft.com/en-us/excel-help/rate-HP005209232.aspx
int FINANCIAL_MAX_ITERATIONS = 20;//Bet accuracy with 128
double FINANCIAL_PRECISION = 0.0000001;//1.0e-8
double y, y0, y1, x0, x1 = 0, f = 0, i = 0;
double rate = guess;
if (Math.abs(rate) < FINANCIAL_PRECISION) {
y = pv * (1 + nper * rate) + pmt * (1 + rate * type) * nper + fv;
} else {
f = Math.exp(nper * Math.log(1 + rate));
y = pv * f + pmt * (1 / rate + type) * (f - 1) + fv;
}
y0 = pv + pmt * nper + fv;
y1 = pv * f + pmt * (1 / rate + type) * (f - 1) + fv;
// find root by Newton secant method
i = x0 = 0.0;
x1 = rate;
while ((Math.abs(y0 - y1) > FINANCIAL_PRECISION) && (i < FINANCIAL_MAX_ITERATIONS)) {
rate = (y1 * x0 - y0 * x1) / (y1 - y0);
x0 = x1;
x1 = rate;
if (Math.abs(rate) < FINANCIAL_PRECISION) {
y = pv * (1 + nper * rate) + pmt * (1 + rate * type) * nper + fv;
} else {
f = Math.exp(nper * Math.log(1 + rate));
y = pv * f + pmt * (1 / rate + type) * (f - 1) + fv;
}
y0 = y1;
y1 = y;
++i;
}
return rate;
}
public double simpleCalculateRate(int nper, double pmt, double pv) {
double fv = 0;
//0或省略-期末支付
double type = 0;
//如果省略预期利率,则假设该值为 10%。
double guess = 0.1;
return calculateRate(nper, pmt, pv, fv, type, guess);
}
}

111
plugin-finance-function/src/main/java/com/fr/plugin/UpbaaDate.java

@ -0,0 +1,111 @@
package com.fr.plugin;
/**
*
* @author 小木桩staker 这个类是辅助计算xirr的类 主要是以时间对应现金的形式组成一条现金流 而xirr则是由多条现金流计算出来的
*/
public class UpbaaDate {
public int year;
public int month;
public int day;
public double payment;// 对应的现金
public UpbaaDate(int year, int month, int day, double payment) {
this.year = year;
this.month = month;
this.day = day;
this.payment = payment;
}
/**
*
* @param stringTime
* 格式为2013/02/05
* @param payment 对应的现金
*/
public UpbaaDate(String stringTime, double payment) {
try {
int start = stringTime.indexOf("-")>stringTime.indexOf("/")?stringTime.indexOf("-"):stringTime.indexOf("/");
int end = stringTime.lastIndexOf("-")>stringTime.lastIndexOf("/")?stringTime.lastIndexOf("-"):stringTime.lastIndexOf("/");
String month = stringTime.substring(start + 1, end);
if (month.length() == 1) {
month = "0" + month;
}
String day = stringTime.substring(end + 1);
if (day.length() == 1) {
day = "0" + day;
}
this.year=Integer.parseInt(stringTime.substring(0, 4));
this.month = Integer.parseInt(month);
this.day=Integer.parseInt(day);
} catch (Exception e) {
// TODO: handle exception
}
this.payment=payment;
}
/**
* 使用默认构造方法的话则对应的是当前的时间即今天的时间
*/
public UpbaaDate() {
String stringTime=DateUtil.getNowStringDate("/");
setStringDate(stringTime);
}
/**
* 设置年月日的字符串格式的时间
* @param stringTime 格式为2013/02/05
*/
public void setStringDate(String stringTime){
try {
this.year=Integer.parseInt(stringTime.substring(0, 4));
this.month=Integer.parseInt(stringTime.substring(5, 7));
this.day=Integer.parseInt(stringTime.substring(8, 10));
} catch (Exception e) {
// TODO: handle exception
}
}
/**
* 获得1970年到现在的天数
* @return long
*/
public long getDaysFrom1970(){
return DateUtil.getDaysFrom1970(year, month, day);
}
/**
* 获得字符串的日期
* @param split 分隔符 -
* @return 2013-02-22
*/
public String getStringDate(String split){
if(split==null){
split="-";
}
StringBuffer stringDate=new StringBuffer();
stringDate.append(year).append(split);
if(month<10){
stringDate.append(0).append(month);
}else{
stringDate.append(month);
}
stringDate.append(split);
if(day<10){
stringDate.append(0).append(day);
}else{
stringDate.append(day);
}
return stringDate.toString();
}
public static void main(String[] args) {
String a = "2020/7/3";
int year=Integer.parseInt(a.substring(0, 4));
int month=Integer.parseInt(a.substring(5, 7));
int day=Integer.parseInt(a.substring(8, 10));
}
}

136
plugin-finance-function/src/main/java/com/fr/plugin/XIRR.java

@ -0,0 +1,136 @@
package com.fr.plugin;
import com.fr.general.FArray;
import com.fr.general.GeneralUtils;
import com.fr.intelli.record.Focus;
import com.fr.intelli.record.Original;
import com.fr.plugin.context.PluginContexts;
import com.fr.record.analyzer.EnableMetrics;
import com.fr.script.AbstractFunction;
import com.fr.stable.StringUtils;
import com.fr.stable.exception.FormulaException;
import com.fr.stable.fun.Authorize;
import java.math.BigDecimal;
import java.util.ArrayList;
/**
* @file: PACKAGE_NAME.XIRR
* @desc:
* @date:2020/7/7 17:41
* @author:yanghui
**/
@EnableMetrics
@Authorize(callSignKey = FinanceFunctionConstants.PLUGIN_ID)
public class XIRR extends AbstractFunction {
private static final String ERROR_VALUE = "#NUM!";
@Override
@Focus(id = "com.fr.plugin.function.finance", text = "Plugin-Test_Function_Finance", source = Original.PLUGIN)
public Object run(Object[] objects) throws FormulaException {
if (PluginContexts.currentContext().isAvailable()) {
return cal(objects);
} else {
return "插件未激活,请购买使用";
}
}
private Object cal(Object[] objects) {
try{
double guess = 0.1;
if (objects.length == 3) {
guess = trans(objects[2]).doubleValue();
}
if (objects.length > 3) {
FArray<BigDecimal> cash = new FArray<BigDecimal>();
FArray<String> date = new FArray<>();
for (int i = 0; i < objects.length; i++) {
if(objects[i] == null|| StringUtils.isBlank(objects[i].toString())){
continue;
}
String trim = GeneralUtils.objectToString(objects[i]).trim();
int start = trim.indexOf("-")>trim.indexOf("/")?trim.indexOf("-"):trim.indexOf("/");
if (start > 0) {
date.add(trim);
}else{
BigDecimal var = new BigDecimal(trim);
if ((var.compareTo(BigDecimal.ONE) <1) && (var.compareTo(BigDecimal.ZERO)>-1)) {
guess = var.doubleValue();
}else {
cash.add(var);
}
}
}
return run(cash, date, guess);
}
return run( transArr( (FArray) objects[0] ), transToString((FArray)objects[1]),guess);
}catch(Exception e){
System.out.println(e);
}
return ERROR_VALUE;
}
/**
* 将数组转换为大数数组
* @param in
* @return
*/
private static FArray<BigDecimal> transArr(FArray in){
FArray<BigDecimal> rt = new FArray<BigDecimal>();
for(int i=0;i<in.length();i++){
Object ele = in.elementAt(i);
if(ele == null|| StringUtils.isBlank(ele.toString())){
continue;
}
rt.add(trans(ele));
}
return rt;
}
/**
* 将其他类型的数字转换为大数保证精度
* @param ele
* @return
*/
private static BigDecimal trans(Object ele){
try{
String val = GeneralUtils.objectToString(ele);
return new BigDecimal(val.trim());
}catch(Exception e){
}
return (BigDecimal) ele;
}
/**
* 将其他类型转换成String
* @param in
* @return
*/
private static FArray<String> transToString(FArray in){
FArray<String> rt = new FArray<>();
for(int i=0;i<in.length();i++){
Object ele = in.elementAt(i);
if(ele == null|| StringUtils.isBlank(ele.toString())){
continue;
}
rt.add(GeneralUtils.objectToString(ele));
}
return rt;
}
private static double run(FArray<BigDecimal> cashflow, FArray<String> dueDate,double guess){
ArrayList<UpbaaDate> list=new ArrayList<UpbaaDate>();
for(int i=0;i<cashflow.length();i++){
UpbaaDate date=new UpbaaDate(dueDate.elementAt(i),cashflow.elementAt(i).doubleValue());
list.add(date);
}
XirrData Xirr=new XirrData(list);
return Xirr.getXirr(guess);
}
}

116
plugin-finance-function/src/main/java/com/fr/plugin/XirrData.java

@ -0,0 +1,116 @@
package com.fr.plugin;
import java.util.ArrayList;
/**
*
* @author yanghui
* 这是真正计算xirr算法的类通过传进来的多条现金流进行计算xirr值和收益值
*/
public class XirrData {
private static final double Max_Rate=99999.9;//最大收益率
private static final double Min_Rate=-0.99999999;//最小收益率
private static final double Critical=0.00000001;//精确值
public static final int Error_Null_List=501;//代表传进来的list为空
public static final int Error_Less_Cash=502;//少于一条现金流
public static final int Error_Date=503;//传进来的现金流的第一条现金流记录的时间不是最早的时间
public static final int Error_First_Payment=504;//第一条现金流的payment的值不为负
/**
* 第一条现金流具体某个时间点的差值天数这个天数应该是所有现金流里面的差值天数最大的
*/
private long startDays = 0;
private ArrayList<UpbaaDate> listUpbaa;
public XirrData(ArrayList<UpbaaDate> listUpbaa){
this.listUpbaa=listUpbaa;
if (listUpbaa != null) {
try {
startDays = listUpbaa.get(0).getDaysFrom1970();
} catch (Exception e) {
}
}
}
/**
* 计算收益值
* @return double
*/
public double getPal(){
if(listUpbaa==null){
return 0.0;
}
double pal=0;
int count=listUpbaa.size();
for (int i = 0; i < count; i++) {
pal=pal+listUpbaa.get(i).payment;
}
return pal;
}
/**
* 通过传进来的多条现金流获得xirr值
* @return 返回收益率
*/
public double getXirr(double guess) {
if(listUpbaa == null){
return Error_Null_List;
}
int count=listUpbaa.size();
if (count <= 1) {
return Error_Less_Cash;// 如果只有一条现金流则返回Error_Less_Cash
}
if (listUpbaa.get(0).payment > 0) {
return Error_First_Payment;
}
for (int i = 0; i < count; i++) {
if (listUpbaa.get(1).getDaysFrom1970() < startDays) {
return Error_Date;// 如果不止一条现金流则判断第一条现金流是否为时间最早的,如果不是的话则返回ERROR_DATE
}
}
boolean isEarn = getXNPVByRate(0) > 0;// 记录是赚钱了还是亏本了
if (isEarn) {
return calXirr(0, Max_Rate,guess);
} else {
return calXirr(Min_Rate, 0,guess);
}
}
private double calXirr(double min,double Max,double guess){
int calculateCount = 50;
double XIRR = guess;
while (calculateCount > 0) {
XIRR = (min + Max) / 2f;
double xnvp = getXNPVByRate(XIRR);
if (xnvp > 0) {
min = XIRR;
} else {
Max = XIRR;
}
if (Math.abs(XIRR) < Critical) {
break;
}
calculateCount--;
}
return XIRR;
}
private double getXNPVByRate(double rate) {
double result = 0;
int size = listUpbaa.size();
for (int i = 0; i < size; i++) {
UpbaaDate date = listUpbaa.get(i);
result = result
+ getOneValue(date.payment, rate, (int) date.getDaysFrom1970()
- (int) startDays);
}
return result;
}
private double getOneValue(double payment, double rate, int dateDistance) {
return payment / ((Math.pow((1 + rate), dateDistance / 365f)));
}
}

1
plugin-finance-function/src/main/resources/com/fr/plugin/demo.properties

@ -0,0 +1 @@
Plugin-Test_Function_Abs=Test FINANCE

1
plugin-finance-function/src/main/resources/com/fr/plugin/demo_zh_CN.properties

@ -0,0 +1 @@
Plugin-Test_Function_Abs=\u6D4B\u8BD5\u8D22\u52A1\u51FD\u6570
Loading…
Cancel
Save