程序员的量化交易之路(11)--命令参数解析库JCommonder学习

转载须注明出处:http://blog.csdn.net/minimicall?viewmode=contentshttp://cloudtrade.top

在学习量化交易平台的过程中,接触到一个参数解析的库,JCommander。今天把它记录一下。

它的官网为:http://www.jcommander.org/

1. 概述

Jcommander是一个非常小的框架,用于解析命令行参数。

可以通过注解来描述你的参数选项:

import com.beust.jcommander.Parameter;

public class JCommanderExample {
  @Parameter
  private List<String> parameters = new ArrayList<String>();

  @Parameter(names = { "-log", "-verbose" }, description = "Level of verbosity")
  private Integer verbose = 1;

  @Parameter(names = "-groups", description = "Comma-separated list of group names to be run")
  private String groups;

  @Parameter(names = "-debug", description = "Debug mode")
  private boolean debug = false;
}

然后你可以通过下面代码来解析命令行参数:

JCommanderExample jct = new JCommanderExample();
String[] argv = { "-log", "2", "-groups", "unit" };
new JCommander(jct, argv);

Assert.assertEquals(jct.verbose.intValue(), 2);

2. 参数类型

你的参数可以是任何类型的。内置类型(Integer,Boolean,等),这些是默认就支持的,当然你可以写一个类型转换器来支持任意你想要支持的类型。

Boolean

@Parameter(names = "-debug", description = "Debug mode")
private boolean debug = false;

如果你想定义一个布尔参数,在默认情况下为真,您可以声明它的参数数量arity 为1。用户将需要显式地指定他们想要的值。

下面程序就是命令行的一个解析案例:

program -debug true
program -debug false

String,Integer,Long

JCommander支持String,Integer,Long类型的解析。

例如:

@Parameter(names = "-log", description = "Level of verbosity")
private Integer verbose = 1;
java Main -log 3

上面的verbose 会接收到3.

当然,下面句子就会抛出异常:

java Main -log test

Lists

当Parameter注解放在一些列表List上时,那么JCommander会理解为该参数可以出现很多次。

@Parameter(names = "-host", description = "The host")
private List<String> hosts = new ArrayList<String>();

java Main -host host1 -verbose -host host2

Password

有时候你不想一个参数明文显示和出现在历史记录里面,比如输入的密码。这个时候你就可以将其配置为密码类型,只需要把password开关打开。

public class ArgsPassword {
  @Parameter(names = "-password", description = "Connection password", password = true)
  private String password;
}

当你执行程序时,就会有下面的提示:

Value for -password (Connection password):

当然,你也可以选择显示输入的密码,将echoInput设置为true:

public class ArgsPassword {
  @Parameter(names = "-password", description = "Connection password", password = true, echoInput = true)
  private String password;
}

3. 自定义类型

通过注解(By annotation)

JCommander是支持内置类型的参数配置。但更多时候吧,你需要输入一些更为复杂的类型。比如说,文件、主机名、列表等。。。。为了达到这个目的,你需要自己去实现下面这个转换接口:

public interface IStringConverter<T> {
  T convert(String value);
}

例如,下面是一个将string转换为File(文件)的转换器:

public class FileConverter implements IStringConverter<File> {
  @Override
  public File convert(String value) {
    return new File(value);
  }
}

然后呢,你就可以将该转换器通过Parameter注解的converter参数进行配置:

@Parameter(names = "-file", converter = FileConverter.class)
File file;

JCommander支持一些常用的转换器(例如都好分割的字符串转成List<String>)

By factory(通过工厂)

上面的File file 用一次,就得使用一次converter=FileConverter.class。好麻烦不?如果要用多次,能不能省掉它呢。可以。

需要通过下面接口:

public interface IStringConverterFactory {
  <T> Class<? extends IStringConverter<T>> getConverter(Class<T> forType);
}

我们看下面这个例子,需要解析一个host:port参数:

java App -target example.com:8080

你需要定义下面holder类:

public class HostPort {
  private String host;
  private Integer port;
}

converter转换器类:

class HostPortConverter implements IStringConverter<HostPort> {
  @Override
  public HostPort convert(String value) {
    HostPort result = new HostPort();
    String[] s = value.split(":");
    result.host = s[0];
    result.port = Integer.parseInt(s[1]);

    return result;
  }
}

工厂类:

public class Factory implements IStringConverterFactory {
  public Class<? extends IStringConverter<?>> getConverter(Class forType) {
    if (forType.equals(HostPort.class)) return HostPortConverter.class;
    else return null;
  }

使用:

public class ArgsConverterFactory {
  @Parameter(names = "-hostport")
  private HostPort hostPort;
}

看到了吧,没有再用converter参数了。

当然,你需要将工厂缴入到JCommander对象中:

ArgsConverterFactory a = new ArgsConverterFactory();
JCommander jc = new JCommander(a);
jc.addConverterFactory(new Factory());
jc.parse("-hostport", "example.com:8080");

Assert.assertEquals(a.hostPort.host, "example.com");
Assert.assertEquals(a.hostPort.port.intValue(), 8080);

4. 参数验证

你可以通过下面的接口来做一些早期的参数验证工作:

public interface IParameterValidator {
 /**
   * Validate the parameter.
   *
   * @param name The name of the parameter (e.g. "-host").
   * @param value The value of the parameter that we need to validate
   *
   * @throws ParameterException Thrown if the value of the parameter is invalid.
   */
  void validate(String name, String value) throws ParameterException;
}

下面这例子就能够保证输入的数字一定大于等于0,即正数:

public class PositiveInteger implements IParameterValidator {
 public void validate(String name, String value)
      throws ParameterException {
    int n = Integer.parseInt(value);
    if (n < 0) {
      throw new ParameterException("Parameter " + name + " should be positive (found " + value +")");
    }
  }
}

使用例子:

@Parameter(names = "-age", validateWith = PositiveInteger.class)
private Integer age;

5 主参数(Main parameter)

到目前为止,你会发现每个参数都有一个names参数。JCommander允许且只允许你配置一个没有名字的参数,它会接受所有没有名字的参数。

例如:

@Parameter(description = "Files")
private List<String> files = new ArrayList<String>();

@Parameter(names = "-debug", description = "Debugging level")
private Integer debug = 1;

解析:

java Main -debug file1 file2

那么 files域会接收到"file1","file2"。

6. 私有参数(Private parameters)

参数可以是私有的:

public class ArgsPrivate {
  @Parameter(names = "-verbose")
  private Integer verbose = 1;

  public Integer getVerbose() {
    return verbose;
  }
}
ArgsPrivate args = new ArgsPrivate();
new JCommander(args, "-verbose", "3");
Assert.assertEquals(args.getVerbose().intValue(), 3);

7. 参数分隔符(Parameter separators)

默认情况下,参数是通过空白符分割的。但你可以改变为:

java Main -log:3

或者:

java Main -level=42

你可以定义分隔符:

@Parameters(separators = "=")
public class SeparatorEqual {
  @Parameter(names = "-level")
  private Integer level = 2;
}

8. 多描述(Multiple description)

直接上例子吧:

public class ArgsMaster {
  @Parameter(names = "-master")
  private String master;
}

public class ArgsSlave {
  @Parameter(names = "-slave")
  private String slave;
}

ArgsMaster m = new ArgsMaster();
ArgsSlave s = new ArgsSlave();
String[] argv = { "-master", "master", "-slave", "slave" };
new JCommander(new Object[] { m , s }, argv);

Assert.assertEquals(m.master, "master");
Assert.assertEquals(s.slave, "slave");

9. @语法

JCommander支持@语法,允许你将参数写到文件里面,然后通过@符加载。例如:

-verbose
file1
file2
file3

java Main @/tmp/parameters

10. Arities(参数的多个值)

一个参数会接收多个值,例如:

java Main -pairs slave master foo.xml

这个-pairs需要接收2个值,(也就是不需要foo.xml),那么需要定义arity=2,如下:

@Parameter(names = "-pairs", arity = 2, description = "Pairs")
private List<String> pairs;

当然,内置类型都不需要定义这个参数。

你可以定义参数接收无限个值,例如:

program -foo a1 a2 a3 -bar
program -foo a1 -bar

即,变长的,他需要设定variableArity参数:

@Parameter(names = "-foo", variableArity = true)
public List<String> foo = new ArrayList<String>();

11. 为参数取多个名字

你可以为一个参数取多个名字:

@Parameter(names = { "-d", "--outputDirectory" }, description = "Directory")
private String outputDirectory;

下面都是可以的:

java Main -d /tmp
java Main --outputDirectory /tmp

好了,还有更多的细节,读者可以自行到其官网学习了。今天就到这里。。。。。。

时间: 2024-07-31 00:41:10

程序员的量化交易之路(11)--命令参数解析库JCommonder学习的相关文章

程序员的量化交易之路(1)----规划开篇

其实,一直对量化交易有一定的理解和情节.早在中大读研究生的时候实验室师兄,已经去了中国平安核心投资团队,做高频交易研究的国源师兄的影响,就开始对金融世界产生了浓厚的兴趣.看了丁磊编著的<量化投资--策略与技术>和艾琳.奥尔德里奇的<高频交易>,反复的看,但是都入不了味,现在回过头来想,一个连股都不炒的人怎么可能入味呢.对一些金融的基本概念都不懂. 2013年7月出社会工作后,在10月份确立目标.需要炒股,而且需要一个深入的理解金融的世界.所以确定去考一个证券从业考试,选了证券基础和

程序员的量化交易之路(24)--Cointrader之RemoteEvent远程事件实体(11)

转载需注明出处:http://blog.csdn.net/minimicall,http://cloudtrader.top/ 在量化交易系统中,有些事件是远端传来的,比如股票的价格数据等.所以,在这一节我们定义了一个远端事件实体. 它是一个基类,并不单独生成数据表.具体代码如下: package org.cryptocoinpartners.schema; import javax.annotation.Nullable; import javax.persistence.Basic; imp

程序员的量化交易之路(2)----Esper文档学习之技术概览(1)

转载请注明出处:http://blog.csdn.net/minimicall/ 在接下来的20个工作日中,我将坚持翻译或者略翻译Esper的官方文档. 为什么需要学习Esper,因为我们需要理解复合事件处理 Complex Event Processing (CEP).在量化交易系统中,CEP是必不可少的.它负责处理海量的实时事件. 关于CEP更多知识,大家可以翻阅网络相关资料.我这里集中在学习开源的CEP系统,Esper.. 今天开始第一篇:技术概览. 1. CEP和事件序列分析 Esper

程序员的量化交易之路(13)--Cointrader类图(1)

转载须注明出处:http://blog.csdn.net/minimicall?viewmode=contents, htpp://cloudtrader.top 今天开始正式切入到Cointrader的源码分析学习中,其主页为:https://github.com/timolson/cointrader. 它是基于Esper的一个比特币云交易托管平台.和我想做的事情比较相近.而且虽然现在没什么功能,但代码量相对少,对于学习非常好. 下面是它的一个类图.: 后面我们会根据这个类图一步步的剖析整个

程序员的量化交易之路(39)--Lean之BacktestingRealTimeHandler回测实时时间事件处理7

</pre>转载需注明出处:<a target=_blank href="http://blog.csdn.net/minimicall?viewmode=contents">http://blog.csdn.net/minimicall?viewmode=contents</a>,<a target=_blank href="http://cloudtrade.top/">http://cloudtrade.top/

程序员的量化交易之路(38)--Lean之实时事件处理接口IRealTimeHandler和RealTimeEvent6

转载需注明出处:http://blog.csdn.net/minimicall?viewmode=contents,http://cloudtrade.top/ 这节开始我们要开始说明另外一个模块:实时事件处理模块. 这个模块的工作是什么呢.它就是用来设置一些在特定时间需要执行的任务.比如,每天开盘的时候,你可以做一个什么动作,比如每天收盘的时候你也可以做一个动作.当然还有更为广泛的运用. 在Lean中,是开启一个单独的线程来处理这种定时任务的. 实时事件:RealTimeEvent 实时事件处

程序员的量化交易之路(36)--Lean之数据读取SubscriptionDataReader4

转载需注明出处:http://blog.csdn.net/minimicall?viewmode=contents,http://cloudtrade.top 数据读取需要定义一个读者.直接见下面代码: namespace QuantConnect.Lean.Engine.DataFeeds { /******************************************************** * CLASS DEFINITIONS ***********************

程序员的量化交易之路(35)--Lean之DataFeed数据槽3

转载需注明出处:http://blog.csdn.net/minimicall,http://cloudtrade.top/ Lean引擎的模块划分非常的规范.其中DataFeed是数据槽,就是供应数据的模块. 1. IDataFeed 接口 模块的接口为: namespace QuantConnect.Lean.Engine.DataFeeds { /// <summary> /// Datafeed interface for creating custom datafeed source

程序员的量化交易之路(29)--Cointrader之Tick实体(16)

转载需注明出处:http://blog.csdn.net/minimicall,http://cloudtrade.top Tick:什么是Tick,在交易平台中非常常见,其实就 单笔交易时某只证券的基本数据. 我们通过代码来学习吧: package org.cryptocoinpartners.schema; import javax.annotation.Nullable; import javax.persistence.Entity; import javax.persistence.M